diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -171,22 +171,23 @@ /// Header-search options used to initialize this header search. std::shared_ptr HSOpts; - /// Mapping from SearchDir to HeaderSearchOptions::UserEntries indices. - llvm::DenseMap SearchDirToHSEntry; - DiagnosticsEngine &Diags; FileManager &FileMgr; + /// The allocator owning search directories. + llvm::SpecificBumpPtrAllocator SearchDirsAlloc; /// \#include search path information. Requests for \#include "x" search the /// directory of the \#including file first, then each directory in SearchDirs /// consecutively. Requests for search the current dir first, then each /// directory in SearchDirs, starting at AngledDirIdx, consecutively. If /// NoCurDirSearch is true, then the check for the file in the current /// directory is suppressed. - std::vector SearchDirs; - /// Whether the DirectoryLookup at the corresponding index in SearchDirs has - /// been successfully used to lookup a file. - std::vector SearchDirsUsage; + std::vector SearchDirs; + /// Set of SearchDirs that have been successfully used to lookup a file. + llvm::DenseSet UsedSearchDirs; + /// Mapping from SearchDir to HeaderSearchOptions::UserEntries indices. + llvm::DenseMap SearchDirToHSEntry; + unsigned AngledDirIdx = 0; unsigned SystemDirIdx = 0; bool NoCurDirSearch = false; @@ -294,8 +295,7 @@ /// Add an additional system search path. void AddSystemSearchPath(const DirectoryLookup &dir) { - SearchDirs.push_back(dir); - SearchDirsUsage.push_back(false); + SearchDirs.push_back(storeSearchDir(dir)); } /// Set the list of system header prefixes. @@ -371,6 +371,10 @@ /// already known. void setTarget(const TargetInfo &Target); + using search_dir_iterator = + llvm::pointee_iterator; + using maybe_search_dir_iterator = llvm::Optional; + /// Given a "foo" or \ reference, look up the indicated file, /// return null on failure. /// @@ -408,7 +412,7 @@ /// found. Optional LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, - const DirectoryLookup *FromDir, const DirectoryLookup **CurDir, + maybe_search_dir_iterator FromDir, maybe_search_dir_iterator *CurDir, ArrayRef> Includers, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, @@ -499,7 +503,11 @@ /// Determine which HeaderSearchOptions::UserEntries have been successfully /// used so far and mark their index with 'true' in the resulting bit vector. + // TODO: Use llvm::BitVector instead. std::vector computeUserEntryUsage() const; + /// Return a bit vector of length \c SearchDirs.size() that indicates for each + /// search directory whether it was used. + std::vector getSearchDirUsage() const; /// This method returns a HeaderMap for the specified /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. @@ -629,6 +637,11 @@ void loadTopLevelSystemModules(); private: + /// Stores the given search directory and returns a stable pointer. + DirectoryLookup *storeSearchDir(const DirectoryLookup &Dir) { + return new (SearchDirsAlloc.Allocate()) DirectoryLookup(Dir); + } + /// Lookup a module with the given module name and search-name. /// /// \param ModuleName The name of the module we're looking for. @@ -715,8 +728,9 @@ void cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, unsigned HitIdx, SourceLocation IncludeLoc); /// Note that a lookup at the given include location was successful using the - /// search path at index `HitIdx`. - void noteLookupUsage(unsigned HitIdx, SourceLocation IncludeLoc); + /// given search path. + void noteLookupUsage(const DirectoryLookup *SearchDir, + SourceLocation IncludeLoc); public: /// Retrieve the module map. @@ -738,9 +752,6 @@ const HeaderFileInfo *getExistingFileInfo(const FileEntry *FE, bool WantExternal = true) const; - // Used by external tools - using search_dir_iterator = std::vector::const_iterator; - search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); } search_dir_iterator search_dir_end() const { return SearchDirs.end(); } unsigned search_dir_size() const { return SearchDirs.size(); } @@ -767,9 +778,6 @@ search_dir_iterator system_dir_end() const { return SearchDirs.end(); } - /// Get the index of the given search directory. - Optional searchDirIdx(const DirectoryLookup &DL) const; - /// Retrieve a uniqued framework name. StringRef getUniqueFrameworkName(StringRef Framework); diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -515,7 +515,7 @@ /// /// This allows us to implement \#include_next and find directory-specific /// properties. - const DirectoryLookup *CurDirLookup = nullptr; + HeaderSearch::maybe_search_dir_iterator CurDirLookup = None; /// The current macro we are expanding, if we are expanding a macro. /// @@ -543,7 +543,7 @@ std::unique_ptr TheLexer; PreprocessorLexer *ThePPLexer; std::unique_ptr TheTokenLexer; - const DirectoryLookup *TheDirLookup; + HeaderSearch::maybe_search_dir_iterator TheDirLookup; // The following constructors are completely useless copies of the default // versions, only needed to pacify MSVC. @@ -551,7 +551,7 @@ std::unique_ptr &&TheLexer, PreprocessorLexer *ThePPLexer, std::unique_ptr &&TheTokenLexer, - const DirectoryLookup *TheDirLookup) + HeaderSearch::maybe_search_dir_iterator TheDirLookup) : CurLexerKind(std::move(CurLexerKind)), TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), ThePPLexer(std::move(ThePPLexer)), @@ -1367,7 +1367,7 @@ /// start lexing tokens from it instead of the current buffer. /// /// Emits a diagnostic, doesn't enter the file, and returns true on error. - bool EnterSourceFile(FileID FID, const DirectoryLookup *Dir, + bool EnterSourceFile(FileID FID, HeaderSearch::maybe_search_dir_iterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile = true); /// Add a Macro to the top of the include stack and start lexing @@ -2050,8 +2050,10 @@ /// reference is for system \#include's or not (i.e. using <> instead of ""). Optional LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, - const DirectoryLookup *FromDir, const FileEntry *FromFile, - const DirectoryLookup **CurDir, SmallVectorImpl *SearchPath, + HeaderSearch::maybe_search_dir_iterator FromDir, + const FileEntry *FromFile, + HeaderSearch::maybe_search_dir_iterator *CurDir, + SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache = false); @@ -2061,7 +2063,9 @@ /// /// This allows us to implement \#include_next and find directory-specific /// properties. - const DirectoryLookup *GetCurDirLookup() { return CurDirLookup; } + HeaderSearch::maybe_search_dir_iterator GetCurDirLookup() { + return CurDirLookup; + } /// Return true if we're in the top-level file, not in a \#include. bool isInPrimaryFile() const; @@ -2223,7 +2227,8 @@ /// Add a lexer to the top of the include stack and /// start lexing tokens from it instead of the current buffer. - void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + void EnterSourceFileWithLexer(Lexer *TheLexer, + HeaderSearch::maybe_search_dir_iterator Dir); /// Set the FileID for the preprocessor predefines. void setPredefinesFileID(FileID FID) { @@ -2300,23 +2305,24 @@ }; Optional LookupHeaderIncludeOrImport( - const DirectoryLookup **CurDir, StringRef &Filename, + HeaderSearch::maybe_search_dir_iterator *CurDir, StringRef &Filename, SourceLocation FilenameLoc, CharSourceRange FilenameRange, const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, - bool &IsMapped, const DirectoryLookup *LookupFrom, + bool &IsMapped, HeaderSearch::maybe_search_dir_iterator LookupFrom, const FileEntry *LookupFromFile, StringRef &LookupFilename, SmallVectorImpl &RelativePath, SmallVectorImpl &SearchPath, ModuleMap::KnownHeader &SuggestedModule, bool isAngled); // File inclusion. - void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok, - const DirectoryLookup *LookupFrom = nullptr, - const FileEntry *LookupFromFile = nullptr); - ImportAction - HandleHeaderIncludeOrImport(SourceLocation HashLoc, Token &IncludeTok, - Token &FilenameTok, SourceLocation EndLoc, - const DirectoryLookup *LookupFrom = nullptr, - const FileEntry *LookupFromFile = nullptr); + void HandleIncludeDirective( + SourceLocation HashLoc, Token &Tok, + HeaderSearch::maybe_search_dir_iterator LookupFrom = None, + const FileEntry *LookupFromFile = nullptr); + ImportAction HandleHeaderIncludeOrImport( + SourceLocation HashLoc, Token &IncludeTok, Token &FilenameTok, + SourceLocation EndLoc, + HeaderSearch::maybe_search_dir_iterator LookupFrom = None, + const FileEntry *LookupFromFile = nullptr); void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); void HandleImportDirective(SourceLocation HashLoc, Token &Tok); diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -311,7 +311,7 @@ SmallVector Headers; for (StringRef Name : ModuleHeaders) { Optional FE = HS.LookupFile( - Name, SourceLocation(), /*Angled*/ false, nullptr, nullptr, None, + Name, SourceLocation(), /*Angled*/ false, None, nullptr, None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!FE) { CI.getDiagnostics().Report(diag::err_module_header_file_not_found) diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -542,7 +542,7 @@ } else { // Lookup file via Preprocessor, like a #include. Optional File = - PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr, + PP->LookupFile(Pos, Filename, false, None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin), diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -256,7 +256,7 @@ /*LoadedOffset=*/0, NewLoc); // NewLoc only used for diags. - if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) + if (PP.EnterSourceFile(FID, /*DirLookup=*/None, NewLoc)) return llvm::make_error("Parsing failed. " "Cannot enter source file.", std::error_code()); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -115,19 +115,24 @@ llvm::DenseMap searchDirToHSEntry) { assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() && "Directory indices are unordered"); - SearchDirs = std::move(dirs); - SearchDirsUsage.assign(SearchDirs.size(), false); + SearchDirsAlloc.DestroyAll(); + SearchDirs.clear(); + for (const DirectoryLookup &Dir : dirs) + SearchDirs.push_back(storeSearchDir(Dir)); + UsedSearchDirs.clear(); + SearchDirToHSEntry.clear(); + for (const auto &Entry : searchDirToHSEntry) + SearchDirToHSEntry.insert({SearchDirs[Entry.first], Entry.second}); + AngledDirIdx = angledDirIdx; SystemDirIdx = systemDirIdx; NoCurDirSearch = noCurDirSearch; - SearchDirToHSEntry = std::move(searchDirToHSEntry); //LookupFileCache.clear(); } void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) { unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx; - SearchDirs.insert(SearchDirs.begin() + idx, dir); - SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false); + SearchDirs.insert(SearchDirs.begin() + idx, storeSearchDir(dir)); if (!isAngled) AngledDirIdx++; SystemDirIdx++; @@ -135,10 +140,9 @@ std::vector HeaderSearch::computeUserEntryUsage() const { std::vector UserEntryUsage(HSOpts->UserEntries.size()); - for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) { - // Check whether this DirectoryLookup has been successfully used. - if (SearchDirsUsage[I]) { - auto UserEntryIdxIt = SearchDirToHSEntry.find(I); + for (const DirectoryLookup *SearchDir : UsedSearchDirs) { + if (UsedSearchDirs.contains(SearchDir)) { + auto UserEntryIdxIt = SearchDirToHSEntry.find(SearchDir); // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry. if (UserEntryIdxIt != SearchDirToHSEntry.end()) UserEntryUsage[UserEntryIdxIt->second] = true; @@ -147,6 +151,14 @@ return UserEntryUsage; } +std::vector HeaderSearch::getSearchDirUsage() const { + std::vector SearchDirUsage(SearchDirs.size()); + for (unsigned I = 0, E = SearchDirs.size(); I < E; ++I) + if (UsedSearchDirs.contains(SearchDirs[I])) + SearchDirUsage[I] = true; + return SearchDirUsage; +} + /// CreateHeaderMap - This method returns a HeaderMap for the specified /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { @@ -301,21 +313,23 @@ SourceLocation ImportLoc, bool AllowExtraModuleMapSearch) { Module *Module = nullptr; - unsigned Idx; + DirectoryLookup *SearchDir = nullptr; // Look through the various header search paths to load any available module // maps, searching for a module map that describes this module. - for (Idx = 0; Idx != SearchDirs.size(); ++Idx) { - if (SearchDirs[Idx].isFramework()) { + for (unsigned Idx = 0; Idx != SearchDirs.size(); ++Idx) { + SearchDir = SearchDirs[Idx]; + + if (SearchDirs[Idx]->isFramework()) { // Search for or infer a module map for a framework. Here we use // SearchName rather than ModuleName, to permit finding private modules // named FooPrivate in buggy frameworks named Foo. SmallString<128> FrameworkDirName; - FrameworkDirName += SearchDirs[Idx].getFrameworkDir()->getName(); + FrameworkDirName += SearchDirs[Idx]->getFrameworkDir()->getName(); llvm::sys::path::append(FrameworkDirName, SearchName + ".framework"); if (auto FrameworkDir = FileMgr.getDirectory(FrameworkDirName)) { bool IsSystem - = SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User; + = SearchDirs[Idx]->getDirCharacteristic() != SrcMgr::C_User; Module = loadFrameworkModule(ModuleName, *FrameworkDir, IsSystem); if (Module) break; @@ -325,12 +339,12 @@ // FIXME: Figure out how header maps and module maps will work together. // Only deal with normal search directories. - if (!SearchDirs[Idx].isNormalDir()) + if (!SearchDirs[Idx]->isNormalDir()) continue; - bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory(); + bool IsSystem = SearchDirs[Idx]->isSystemHeaderDirectory(); // Search for a module map file in this directory. - if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, + if (loadModuleMapFile(SearchDirs[Idx]->getDir(), IsSystem, /*IsFramework*/false) == LMM_NewlyLoaded) { // We just loaded a module map file; check whether the module is // available now. @@ -342,7 +356,7 @@ // Search for a module map in a subdirectory with the same name as the // module. SmallString<128> NestedModuleMapDirName; - NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName(); + NestedModuleMapDirName = SearchDirs[Idx]->getDir()->getName(); llvm::sys::path::append(NestedModuleMapDirName, ModuleName); if (loadModuleMapFile(NestedModuleMapDirName, IsSystem, /*IsFramework*/false) == LMM_NewlyLoaded){ @@ -354,13 +368,13 @@ // If we've already performed the exhaustive search for module maps in this // search directory, don't do it again. - if (SearchDirs[Idx].haveSearchedAllModuleMaps()) + if (SearchDirs[Idx]->haveSearchedAllModuleMaps()) continue; // Load all module maps in the immediate subdirectories of this search // directory if ModuleName was from @import. if (AllowExtraModuleMapSearch) - loadSubdirectoryModuleMaps(SearchDirs[Idx]); + loadSubdirectoryModuleMaps(*SearchDirs[Idx]); // Look again for the module. Module = ModMap.findModule(ModuleName); @@ -369,7 +383,7 @@ } if (Module) - noteLookupUsage(Idx, ImportLoc); + noteLookupUsage(SearchDir, ImportLoc); return Module; } @@ -495,7 +509,7 @@ // The case where the target file **exists** is handled by callee of this // function as part of the regular logic that applies to include search paths. // The case where the target file **does not exist** is handled here: - HS.noteLookupUsage(*HS.searchDirIdx(*this), IncludeLoc); + HS.noteLookupUsage(this, IncludeLoc); return None; } @@ -703,13 +717,14 @@ void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, unsigned HitIdx, SourceLocation Loc) { CacheLookup.HitIdx = HitIdx; - noteLookupUsage(HitIdx, Loc); + noteLookupUsage(SearchDirs[HitIdx], Loc); } -void HeaderSearch::noteLookupUsage(unsigned HitIdx, SourceLocation Loc) { - SearchDirsUsage[HitIdx] = true; +void HeaderSearch::noteLookupUsage(const DirectoryLookup *SearchDir, + SourceLocation Loc) { + UsedSearchDirs.insert(SearchDir); - auto UserEntryIdxIt = SearchDirToHSEntry.find(HitIdx); + auto UserEntryIdxIt = SearchDirToHSEntry.find(SearchDir); if (UserEntryIdxIt != SearchDirToHSEntry.end()) Diags.Report(Loc, diag::remark_pp_search_path_usage) << HSOpts->UserEntries[UserEntryIdxIt->second].Path; @@ -831,14 +846,15 @@ /// search is needed. Microsoft mode will pass all \#including files. Optional HeaderSearch::LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, - const DirectoryLookup *FromDir, const DirectoryLookup **CurDirArg, + HeaderSearch::maybe_search_dir_iterator FromDir, + HeaderSearch::maybe_search_dir_iterator *CurDirArg, ArrayRef> Includers, SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache, bool BuildSystemModule) { - const DirectoryLookup *CurDirLocal = nullptr; - const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal; + HeaderSearch::maybe_search_dir_iterator CurDirLocal; + auto &CurDir = CurDirArg ? *CurDirArg : CurDirLocal; if (IsMapped) *IsMapped = false; @@ -851,7 +867,7 @@ // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { - CurDir = nullptr; + CurDir.reset(); // If this was an #include_next "/absolute/file", fail. if (FromDir) @@ -958,7 +974,7 @@ } } - CurDir = nullptr; + CurDir.reset(); // If this is a system #include, ignore the user #include locs. unsigned i = isAngled ? AngledDirIdx : 0; @@ -966,7 +982,7 @@ // If this is a #include_next request, start searching after the directory the // file was found in. if (FromDir) - i = FromDir-&SearchDirs[0]; + i = *FromDir - SearchDirs.begin(); // Cache all of the lookups performed by this method. Many headers are // multiply included, and the "pragma once" optimization prevents them from @@ -999,7 +1015,7 @@ bool InUserSpecifiedSystemFramework = false; bool IsInHeaderMap = false; bool IsFrameworkFoundInDir = false; - Optional File = SearchDirs[i].LookupFile( + Optional File = SearchDirs[i]->LookupFile( Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule, SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir, IsInHeaderMap, MappedName); @@ -1021,11 +1037,11 @@ if (!File) continue; - CurDir = &SearchDirs[i]; + CurDir = SearchDirs.begin() + i; // This file is a system header or C++ unfriendly if the dir is. HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry()); - HFI.DirInfo = CurDir->getDirCharacteristic(); + HFI.DirInfo = (*CurDir)->getDirCharacteristic(); // If the directory characteristic is User but this framework was // user-specified to be treated as a system framework, promote the @@ -1045,12 +1061,12 @@ // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. - if (CurDir->isHeaderMap() && isAngled) { + if ((*CurDir)->isHeaderMap() && isAngled) { size_t SlashPos = Filename.find('/'); if (SlashPos != StringRef::npos) HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos)); - if (CurDir->isIndexHeaderMap()) + if ((*CurDir)->isIndexHeaderMap()) HFI.IndexHeaderMapHeader = 1; } @@ -1443,13 +1459,6 @@ + FrameworkMap.getAllocator().getTotalMemory(); } -Optional HeaderSearch::searchDirIdx(const DirectoryLookup &DL) const { - for (unsigned I = 0; I < SearchDirs.size(); ++I) - if (&SearchDirs[I] == &DL) - return I; - return None; -} - StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) { return FrameworkNames.insert(Framework).first->first(); } @@ -1777,11 +1786,11 @@ 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()) { + bool IsSystem = SearchDirs[Idx]->isSystemHeaderDirectory(); + if (SearchDirs[Idx]->isFramework()) { std::error_code EC; SmallString<128> DirNative; - llvm::sys::path::native(SearchDirs[Idx].getFrameworkDir()->getName(), + llvm::sys::path::native(SearchDirs[Idx]->getFrameworkDir()->getName(), DirNative); // Search each of the ".framework" directories to load them as modules. @@ -1805,16 +1814,16 @@ } // FIXME: Deal with header maps. - if (SearchDirs[Idx].isHeaderMap()) + if (SearchDirs[Idx]->isHeaderMap()) continue; // Try to load a module map file for the search directory. - loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, + loadModuleMapFile(SearchDirs[Idx]->getDir(), IsSystem, /*IsFramework*/ false); // Try to load module map files for immediate subdirectories of this // search directory. - loadSubdirectoryModuleMaps(SearchDirs[Idx]); + loadSubdirectoryModuleMaps(*SearchDirs[Idx]); } } @@ -1830,14 +1839,13 @@ // 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()) { + 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()); + loadModuleMapFile(SearchDirs[Idx]->getDir(), + SearchDirs[Idx]->isSystemHeaderDirectory(), + SearchDirs[Idx]->isFramework()); } } @@ -1935,15 +1943,15 @@ bool BestPrefixIsFramework = false; for (unsigned I = 0; I != SearchDirs.size(); ++I) { - if (SearchDirs[I].isNormalDir()) { - StringRef Dir = SearchDirs[I].getDir()->getName(); + if (SearchDirs[I]->isNormalDir()) { + StringRef Dir = SearchDirs[I]->getDir()->getName(); if (CheckDir(Dir)) { if (IsSystem) *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false; BestPrefixIsFramework = false; } - } else if (SearchDirs[I].isFramework()) { - StringRef Dir = SearchDirs[I].getFrameworkDir()->getName(); + } else if (SearchDirs[I]->isFramework()) { + StringRef Dir = SearchDirs[I]->getFrameworkDir()->getName(); if (CheckDir(Dir)) { if (IsSystem) *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false; @@ -1964,11 +1972,11 @@ // key from header name is user prefered name for the include file. StringRef Filename = File.drop_front(BestPrefixLength); for (unsigned I = 0; I != SearchDirs.size(); ++I) { - if (!SearchDirs[I].isHeaderMap()) + if (!SearchDirs[I]->isHeaderMap()) continue; StringRef SpelledFilename = - SearchDirs[I].getHeaderMap()->reverseLookupFilename(Filename); + SearchDirs[I]->getHeaderMap()->reverseLookupFilename(Filename); if (!SpelledFilename.empty()) { Filename = SpelledFilename; BestPrefixIsFramework = false; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -817,13 +817,13 @@ Optional Preprocessor::LookupFile( SourceLocation FilenameLoc, StringRef Filename, bool isAngled, - const DirectoryLookup *FromDir, const FileEntry *FromFile, - const DirectoryLookup **CurDirArg, SmallVectorImpl *SearchPath, - SmallVectorImpl *RelativePath, + HeaderSearch::maybe_search_dir_iterator FromDir, const FileEntry *FromFile, + HeaderSearch::maybe_search_dir_iterator *CurDirArg, + SmallVectorImpl *SearchPath, SmallVectorImpl *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache) { - const DirectoryLookup *CurDirLocal = nullptr; - const DirectoryLookup *&CurDir = CurDirArg ? *CurDirArg : CurDirLocal; + HeaderSearch::maybe_search_dir_iterator CurDirLocal; + auto &CurDir = CurDirArg ? *CurDirArg : CurDirLocal; Module *RequestingModule = getModuleForLocation(FilenameLoc); bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc); @@ -877,8 +877,8 @@ if (FromFile) { // We're supposed to start looking from after a particular file. Search // the include path until we find that file or run out of files. - const DirectoryLookup *TmpCurDir = CurDir; - const DirectoryLookup *TmpFromDir = nullptr; + HeaderSearch::maybe_search_dir_iterator TmpCurDir = CurDir; + HeaderSearch::maybe_search_dir_iterator TmpFromDir; while (Optional FE = HeaderInfo.LookupFile( Filename, FilenameLoc, isAngled, TmpFromDir, &TmpCurDir, Includers, SearchPath, RelativePath, RequestingModule, @@ -886,7 +886,7 @@ /*IsFrameworkFound=*/nullptr, SkipCache)) { // Keep looking as if this file did a #include_next. TmpFromDir = TmpCurDir; - ++TmpFromDir; + ++*TmpFromDir; if (&FE->getFileEntry() == FromFile) { // Found it. FromDir = TmpFromDir; @@ -1783,10 +1783,10 @@ /// routine with functionality shared between \#include, \#include_next and /// \#import. LookupFrom is set when this is a \#include_next directive, it /// specifies the file to start searching from. -void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, - Token &IncludeTok, - const DirectoryLookup *LookupFrom, - const FileEntry *LookupFromFile) { +void Preprocessor::HandleIncludeDirective( + SourceLocation HashLoc, Token &IncludeTok, + HeaderSearch::maybe_search_dir_iterator LookupFrom, + const FileEntry *LookupFromFile) { Token FilenameTok; if (LexHeaderName(FilenameTok)) return; @@ -1830,10 +1830,10 @@ } Optional Preprocessor::LookupHeaderIncludeOrImport( - const DirectoryLookup **CurDir, StringRef& Filename, + HeaderSearch::maybe_search_dir_iterator *CurDir, StringRef& Filename, SourceLocation FilenameLoc, CharSourceRange FilenameRange, const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, - bool &IsMapped, const DirectoryLookup *LookupFrom, + bool &IsMapped, HeaderSearch::maybe_search_dir_iterator LookupFrom, const FileEntry *LookupFromFile, StringRef& LookupFilename, SmallVectorImpl &RelativePath, SmallVectorImpl &SearchPath, ModuleMap::KnownHeader &SuggestedModule, bool isAngled) { @@ -1960,7 +1960,7 @@ /// lookup. Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( SourceLocation HashLoc, Token &IncludeTok, Token &FilenameTok, - SourceLocation EndLoc, const DirectoryLookup *LookupFrom, + SourceLocation EndLoc, HeaderSearch::maybe_search_dir_iterator LookupFrom, const FileEntry *LookupFromFile) { SmallString<128> FilenameBuffer; StringRef Filename = getSpelling(FilenameTok, FilenameBuffer); @@ -2010,7 +2010,7 @@ // Search include directories. bool IsMapped = false; bool IsFrameworkFound = false; - const DirectoryLookup *CurDir; + HeaderSearch::maybe_search_dir_iterator CurDir; SmallString<1024> SearchPath; SmallString<1024> RelativePath; // We get the raw path only if we have 'Callbacks' to which we later pass @@ -2400,21 +2400,21 @@ // #include_next is like #include, except that we start searching after // the current found directory. If we can't do this, issue a // diagnostic. - const DirectoryLookup *Lookup = CurDirLookup; + HeaderSearch::maybe_search_dir_iterator Lookup = CurDirLookup; const FileEntry *LookupFromFile = nullptr; if (isInPrimaryFile() && LangOpts.IsHeaderFile) { // If the main file is a header, then it's either for PCH/AST generation, // or libclang opened it. Either way, handle it as a normal include below // and do not complain about include_next. } else if (isInPrimaryFile()) { - Lookup = nullptr; + Lookup.reset(); Diag(IncludeNextTok, diag::pp_include_next_in_primary); } else if (CurLexerSubmodule) { // Start looking up in the directory *after* the one in which the current // file would be found, if any. assert(CurPPLexer && "#include_next directive in macro?"); LookupFromFile = CurPPLexer->getFileEntry(); - Lookup = nullptr; + Lookup.reset(); } else if (!Lookup) { // The current file was not found by walking the include path. Either it // is the primary file (handled above), or it was found by absolute path, @@ -2423,7 +2423,7 @@ Diag(IncludeNextTok, diag::pp_include_next_absolute_path); } else { // Start looking up in the next directory. - ++Lookup; + ++*Lookup; } return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup, diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -66,9 +66,9 @@ /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. -bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, - SourceLocation Loc, - bool IsFirstIncludeOfFile) { +bool Preprocessor::EnterSourceFile( + FileID FID, HeaderSearch::maybe_search_dir_iterator CurDir, + SourceLocation Loc, bool IsFirstIncludeOfFile) { assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -99,8 +99,8 @@ /// EnterSourceFileWithLexer - Add a source file to the top of the include stack /// and start lexing tokens from it instead of the current buffer. -void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, - const DirectoryLookup *CurDir) { +void Preprocessor::EnterSourceFileWithLexer( + Lexer *TheLexer, HeaderSearch::maybe_search_dir_iterator CurDir) { // Add the current lexer to the include stack. if (CurPPLexer || CurTokenLexer) @@ -136,7 +136,7 @@ } PushIncludeMacroStack(); - CurDirLookup = nullptr; + CurDirLookup.reset(); CurTokenLexer = std::move(TokLexer); if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_TokenLexer; @@ -191,7 +191,7 @@ // Save our current state. PushIncludeMacroStack(); - CurDirLookup = nullptr; + CurDirLookup.reset(); CurTokenLexer = std::move(TokLexer); if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_TokenLexer; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1157,10 +1157,10 @@ /// EvaluateHasIncludeCommon - Process a '__has_include("path")' /// or '__has_include_next("path")' expression. /// Returns true if successful. -static bool EvaluateHasIncludeCommon(Token &Tok, - IdentifierInfo *II, Preprocessor &PP, - const DirectoryLookup *LookupFrom, - const FileEntry *LookupFromFile) { +static bool +EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, Preprocessor &PP, + HeaderSearch::maybe_search_dir_iterator LookupFrom, + const FileEntry *LookupFromFile) { // Save the location of the current token. If a '(' is later found, use // that location. If not, use the end of this location instead. SourceLocation LParenLoc = Tok.getLocation(); @@ -1248,7 +1248,7 @@ /// Returns true if successful. static bool EvaluateHasInclude(Token &Tok, IdentifierInfo *II, Preprocessor &PP) { - return EvaluateHasIncludeCommon(Tok, II, PP, nullptr, nullptr); + return EvaluateHasIncludeCommon(Tok, II, PP, None, nullptr); } /// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression. @@ -1260,26 +1260,26 @@ // issue a diagnostic. // FIXME: Factor out duplication with // Preprocessor::HandleIncludeNextDirective. - const DirectoryLookup *Lookup = PP.GetCurDirLookup(); + HeaderSearch::maybe_search_dir_iterator Lookup = PP.GetCurDirLookup(); const FileEntry *LookupFromFile = nullptr; if (PP.isInPrimaryFile() && PP.getLangOpts().IsHeaderFile) { // If the main file is a header, then it's either for PCH/AST generation, // or libclang opened it. Either way, handle it as a normal include below // and do not complain about __has_include_next. } else if (PP.isInPrimaryFile()) { - Lookup = nullptr; + Lookup.reset(); PP.Diag(Tok, diag::pp_include_next_in_primary); } else if (PP.getCurrentLexerSubmodule()) { // Start looking up in the directory *after* the one in which the current // file would be found, if any. assert(PP.getCurrentLexer() && "#include_next directive in macro?"); LookupFromFile = PP.getCurrentLexer()->getFileEntry(); - Lookup = nullptr; + Lookup.reset(); } else if (!Lookup) { PP.Diag(Tok, diag::pp_include_next_absolute_path); } else { // Start looking up in the next directory. - ++Lookup; + ++*Lookup; } return EvaluateHasIncludeCommon(Tok, II, PP, Lookup, LookupFromFile); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -330,7 +330,7 @@ Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc, StrVal.size(), *this); - EnterSourceFileWithLexer(TL, nullptr); + EnterSourceFileWithLexer(TL, None); // With everything set up, lex this as a #pragma directive. HandlePragmaDirective({PIK__Pragma, PragmaLoc}); @@ -526,7 +526,7 @@ return llvm::None; // Search include directories for this file. - File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, + File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -538,7 +538,7 @@ // a main file. if (!SourceMgr.isLoadedFileID(MainFileID)) { // Enter the main file source buffer. - EnterSourceFile(MainFileID, nullptr, SourceLocation()); + EnterSourceFile(MainFileID, None, SourceLocation()); // If we've been asked to skip bytes in the main file (e.g., as part of a // precompiled preamble), do so now. @@ -561,14 +561,14 @@ setPredefinesFileID(FID); // Start parsing the predefines. - EnterSourceFile(FID, nullptr, SourceLocation()); + EnterSourceFile(FID, None, SourceLocation()); if (!PPOpts->PCHThroughHeader.empty()) { // Lookup and save the FileID for the through header. If it isn't found // in the search path, it's a fatal error. Optional File = LookupFile( SourceLocation(), PPOpts->PCHThroughHeader, - /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, + /*isAngled=*/false, /*FromDir=*/None, /*FromFile=*/nullptr, /*CurDir=*/nullptr, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, /*IsFrameworkFound=*/nullptr); diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp b/clang/unittests/Lex/HeaderSearchTest.cpp --- a/clang/unittests/Lex/HeaderSearchTest.cpp +++ b/clang/unittests/Lex/HeaderSearchTest.cpp @@ -23,6 +23,12 @@ namespace clang { namespace { +static std::shared_ptr createTargetOptions() { + auto TargetOpts = std::make_shared(); + TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; + return TargetOpts; +} + // The test fixture. class HeaderSearchTest : public ::testing::Test { protected: @@ -30,12 +36,10 @@ : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS), DiagID(new DiagnosticIDs()), Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), - SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions), + SourceMgr(Diags, FileMgr), TargetOpts(createTargetOptions()), + Target(TargetInfo::CreateTargetInfo(Diags, TargetOpts)), Search(std::make_shared(), SourceMgr, Diags, - LangOpts, Target.get()) { - TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; - Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); - } + LangOpts, Target.get()) {} void addSearchDir(llvm::StringRef Dir) { VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/None, @@ -55,6 +59,27 @@ Search.AddSystemSearchPath(DL); } + void setSearchDirs(llvm::ArrayRef QuotedDirs, + llvm::ArrayRef AngledDirs) { + auto AddPath = [&](StringRef Dir, bool IsAngled) { + VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/None, + /*Group=*/None, llvm::sys::fs::file_type::directory_file); + auto Group = IsAngled ? frontend::IncludeDirGroup::Angled + : frontend::IncludeDirGroup::Quoted; + Search.getHeaderSearchOpts().AddPath(Dir, Group, + /*IsFramework=*/false, + /*IgnoreSysRoot=*/true); + }; + + for (llvm::StringRef Dir : QuotedDirs) + AddPath(Dir, /*IsAngled=*/false); + for (llvm::StringRef Dir : AngledDirs) + AddPath(Dir, /*IsAngled=*/true); + + clang::ApplyHeaderSearchOptions(Search, Search.getHeaderSearchOpts(), + LangOpts, Target->getTriple()); + } + void addHeaderMap(llvm::StringRef Filename, std::unique_ptr Buf, bool isAngled = false) { @@ -71,6 +96,17 @@ Search.AddSearchPath(DL, isAngled); } + void createModule(StringRef Mod) { + std::string ModDir = ("/" + Mod).str(); + std::string ModHeader = (Mod + ".h").str(); + VFS->addFile( + ModDir + "/module.modulemap", 0, + llvm::MemoryBuffer::getMemBufferCopy( + ("module " + Mod + " { header \"" + ModHeader + "\" }").str())); + VFS->addFile(ModDir + "/" + ModHeader, 0, + llvm::MemoryBuffer::getMemBuffer("")); + } + IntrusiveRefCntPtr VFS; FileSystemOptions FileMgrOpts; FileManager FileMgr; @@ -239,7 +275,7 @@ bool IsMapped = false; auto FoundFile = Search.LookupFile( - "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr, + "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/None, /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr, /*SuggestedModule=*/nullptr, &IsMapped, @@ -254,5 +290,31 @@ EXPECT_EQ(FI->Framework.str(), "Foo"); } +TEST_F(HeaderSearchTest, SearchPathUsage) { + Search.getHeaderSearchOpts().ImplicitModuleMaps = true; + + setSearchDirs(/*QuotedDirs=*/{"/M0"}, /*AngledDirs=*/{"/M2", "/M3"}); + createModule("M0"); + createModule("M2"); + createModule("M3"); + + { + Module *M2 = Search.lookupModule("M2"); + EXPECT_NE(M2, nullptr); + EXPECT_EQ(Search.getSearchDirUsage(), (std::vector{0, 1, 0})); + EXPECT_EQ(Search.computeUserEntryUsage(), (std::vector{0, 1, 0})); + } + + addSearchDir("/M1"); + createModule("M1"); + + { + Module *M1 = Search.lookupModule("M1"); + EXPECT_NE(M1, nullptr); + EXPECT_EQ(Search.getSearchDirUsage(), (std::vector{0, 1, 1, 0})); + EXPECT_EQ(Search.computeUserEntryUsage(), (std::vector{0, 1, 0})); + } +} + } // namespace } // namespace clang