diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -892,14 +892,12 @@ } std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const { - std::error_code EC; int MaxVersion = 0; std::string MaxVersionString; SmallString<128> Path(IncludePath); llvm::sys::path::append(Path, "c++"); - for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + for (const auto &Entry : getVFS().dir_range(Path)) { + StringRef VersionText = llvm::sys::path::filename(Entry.path()); int Version; if (VersionText[0] == 'v' && !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -40,13 +40,10 @@ StringRef PackageName) { if (!Cand.isSPACK()) return {}; - std::error_code EC; std::string Prefix = Twine(PackageName + "-" + Cand.SPACKReleaseStr).str(); llvm::SmallVector> SubDirs; - for (llvm::vfs::directory_iterator File = D.getVFS().dir_begin(Cand.Path, EC), - FileEnd; - File != FileEnd && !EC; File.increment(EC)) { - llvm::StringRef FileName = llvm::sys::path::filename(File->path()); + for (const auto &File : D.getVFS().dir_range(Cand.Path)) { + llvm::StringRef FileName = llvm::sys::path::filename(File.path()); if (FileName.startswith(Prefix)) { SubDirs.push_back(FileName); if (SubDirs.size() > 1) @@ -77,10 +74,8 @@ const StringRef Suffix(".bc"); const StringRef Suffix2(".amdgcn.bc"); - std::error_code EC; - for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Path, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef FilePath = LI->path(); + for (const auto &Entry : D.getVFS().dir_range(Path)) { + StringRef FilePath = Entry.path(); StringRef FileName = llvm::sys::path::filename(FilePath); if (!FileName.endswith(Suffix)) continue; @@ -277,11 +272,8 @@ V.tryParse(VerStr); return V; }; - for (llvm::vfs::directory_iterator - File = D.getVFS().dir_begin(D.SysRoot + "/opt", EC), - FileEnd; - File != FileEnd && !EC; File.increment(EC)) { - llvm::StringRef FileName = llvm::sys::path::filename(File->path()); + for (const auto &File : D.getVFS().dir_range(D.SysRoot + "/opt")) { + llvm::StringRef FileName = llvm::sys::path::filename(File.path()); if (!FileName.startswith("rocm-")) continue; if (LatestROCm.empty()) { diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -247,14 +247,10 @@ case ToolChain::CST_Libstdcxx: { SmallString<128> Dir(SysRoot); llvm::sys::path::append(Dir, "include", "c++"); - std::error_code EC; Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; // Walk the subdirs, and find the one with the newest gcc version: - for (llvm::vfs::directory_iterator - LI = getDriver().getVFS().dir_begin(Dir.str(), EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + for (const auto &Entry : getDriver().getVFS().dir_range(Dir)) { + StringRef VersionText = llvm::sys::path::filename(Entry.path()); auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); if (CandidateVersion.Major == -1) continue; diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -227,11 +227,8 @@ } } } else { - std::error_code EC; - for (llvm::vfs::directory_iterator LI = FS.dir_begin(LibDevicePath, EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef FilePath = LI->path(); + for (const auto &Entry : FS.dir_range(LibDevicePath)) { + StringRef FilePath = Entry.path(); StringRef FileName = llvm::sys::path::filename(FilePath); // Process all bitcode filenames that look like // libdevice.compute_XX.YY.bc diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2016,11 +2016,8 @@ // /usr/gcc/ as a prefix. std::string PrefixDir = SysRoot.str() + "/usr/gcc"; - std::error_code EC; - for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + for (const auto &Entry : D.getVFS().dir_range(PrefixDir)) { + StringRef VersionText = llvm::sys::path::filename(Entry.path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); // Filter out obviously bad entries. @@ -2528,22 +2525,18 @@ continue; StringRef LibSuffix = Suffix.LibSuffix; - std::error_code EC; - for (llvm::vfs::directory_iterator - LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + for (const auto &Entry : D.getVFS().dir_range(LibDir + "/" + LibSuffix)) { + StringRef VersionText = llvm::sys::path::filename(Entry.path()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(std::string(LI->path())).second) + if (!CandidateGCCInstallPaths.insert(std::string(Entry.path())).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; if (CandidateVersion <= Version) continue; - if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), + if (!ScanGCCForMultilibs(TargetTriple, Args, Entry.path(), NeedsBiarchSuffix)) continue; diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -135,14 +135,11 @@ std::string Highest; llvm::VersionTuple HighestTuple; - std::error_code EC; - for (llvm::vfs::directory_iterator DirIt = VFS.dir_begin(Directory, EC), - DirEnd; - !EC && DirIt != DirEnd; DirIt.increment(EC)) { - auto Status = VFS.status(DirIt->path()); + for (const auto &Entry : VFS.dir_range(Directory)) { + auto Status = VFS.status(Entry.path()); if (!Status || !Status->isDirectory()) continue; - StringRef CandidateName = llvm::sys::path::filename(DirIt->path()); + StringRef CandidateName = llvm::sys::path::filename(Entry.path()); llvm::VersionTuple Tuple; if (Tuple.tryParse(CandidateName)) // tryParse() returns true on error. continue; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -237,21 +237,19 @@ return; } - std::error_code EC; SmallString<128> DirNative; llvm::sys::path::native((*PCHDir)->getName(), DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); SimpleASTReaderListener Validator(CI.getPreprocessor()); - for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { + for (const auto &Dir : FS.dir_range(DirNative)) { // Check whether this is an AST file. ASTReader::isAcceptableASTFile is not // used here since we're not interested in validating the PCH at this time, // but only to check whether this is a file containing an AST. if (!ASTReader::readASTFileControlBlock( - Dir->path(), FileMgr, CI.getPCHContainerReader(), + Dir.path(), FileMgr, CI.getPCHContainerReader(), /*FindModuleFileExtensions=*/false, Validator, /*ValidateDiagnosticOptions=*/false)) - MDC->addFile(Dir->path()); + MDC->addFile(Dir.path()); } } diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -753,20 +753,17 @@ StringRef PCHInclude = PPOpts.ImplicitPCHInclude; std::string SpecificModuleCachePath = CI.getSpecificModuleCachePath(); if (auto PCHDir = FileMgr.getDirectory(PCHInclude)) { - std::error_code EC; SmallString<128> DirNative; llvm::sys::path::native((*PCHDir)->getName(), DirNative); bool Found = false; llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); - for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), - DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { + for (const auto &Dir : FS.dir_range(DirNative)) { // Check whether this is an acceptable AST file. if (ASTReader::isAcceptableASTFile( - Dir->path(), FileMgr, CI.getPCHContainerReader(), + Dir.path(), FileMgr, CI.getPCHContainerReader(), CI.getLangOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(), SpecificModuleCachePath)) { - PPOpts.ImplicitPCHInclude = std::string(Dir->path()); + PPOpts.ImplicitPCHInclude = std::string(Dir.path()); Found = true; break; } 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 @@ -1784,26 +1784,23 @@ 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. llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); - for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), - DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - if (llvm::sys::path::extension(Dir->path()) != ".framework") + for (const auto &Dir : FS.dir_range(DirNative)) { + if (llvm::sys::path::extension(Dir.path()) != ".framework") continue; auto FrameworkDir = - FileMgr.getDirectory(Dir->path()); + FileMgr.getDirectory(Dir.path()); if (!FrameworkDir) continue; // Load this framework module. - loadFrameworkModule(llvm::sys::path::stem(Dir->path()), *FrameworkDir, + loadFrameworkModule(llvm::sys::path::stem(Dir.path()), *FrameworkDir, IsSystem); } continue; @@ -1852,17 +1849,15 @@ if (SearchDir.haveSearchedAllModuleMaps()) return; - std::error_code EC; SmallString<128> Dir = SearchDir.getDir()->getName(); FileMgr.makeAbsolutePath(Dir); SmallString<128> DirNative; llvm::sys::path::native(Dir, DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); - for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - bool IsFramework = llvm::sys::path::extension(Dir->path()) == ".framework"; + for (const auto &Dir : FS.dir_range(DirNative)) { + bool IsFramework = llvm::sys::path::extension(Dir.path()) == ".framework"; if (IsFramework == SearchDir.isFramework()) - loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(), + loadModuleMapFile(Dir.path(), SearchDir.isSystemHeaderDirectory(), SearchDir.isFramework()); } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -1057,21 +1057,16 @@ Result->InferExportWildcard = true; // Look for subframeworks. - std::error_code EC; SmallString<128> SubframeworksDirName = StringRef(FrameworkDir->getName()); llvm::sys::path::append(SubframeworksDirName, "Frameworks"); llvm::sys::path::native(SubframeworksDirName); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); - for (llvm::vfs::directory_iterator - Dir = FS.dir_begin(SubframeworksDirName, EC), - DirEnd; - Dir != DirEnd && !EC; Dir.increment(EC)) { - if (!StringRef(Dir->path()).endswith(".framework")) + for (const auto &Dir : FS.dir_range(SubframeworksDirName)) { + if (!StringRef(Dir.path()).endswith(".framework")) continue; - if (auto SubframeworkDir = - FileMgr.getDirectory(Dir->path())) { + if (auto SubframeworkDir = FileMgr.getDirectory(Dir.path())) { // Note: as an egregious but useful hack, we use the real path here and // check whether it is actually a subdirectory of the parent directory. // This will not be the case if the 'subframework' is actually a symlink diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -9896,20 +9896,18 @@ const bool isQt = Dirname.startswith("Qt") || Dirname == "ActiveQt"; const bool ExtensionlessHeaders = IsSystem || isQt || Dir.endswith(".framework/Headers"); - std::error_code EC; unsigned Count = 0; - for (auto It = FS.dir_begin(Dir, EC); - !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) { + for (const auto &Entry : FS.dir_range(Dir)) { if (++Count == 2500) // If we happen to hit a huge directory, break; // bail out early so we're not too slow. - StringRef Filename = llvm::sys::path::filename(It->path()); + StringRef Filename = llvm::sys::path::filename(Entry.path()); // To know whether a symlink should be treated as file or a directory, we // have to stat it. This should be cheap enough as there shouldn't be many // symlinks. - llvm::sys::fs::file_type Type = It->type(); + llvm::sys::fs::file_type Type = Entry.type(); if (Type == llvm::sys::fs::file_type::symlink_file) { - if (auto FileStatus = FS.status(It->path())) + if (auto FileStatus = FS.status(Entry.path())) Type = FileStatus->getType(); } switch (Type) { diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -202,6 +202,38 @@ } }; +/// Wrapper for directory_iterator that automatically handles error codes. +class directory_iterator_error_wrapper { + directory_iterator It; + +public: + directory_iterator_error_wrapper(directory_iterator It, std::error_code &EC) + : It(std::move(It)) { + if (EC) + It = directory_iterator(); + } + + directory_iterator_error_wrapper() = default; + + directory_iterator_error_wrapper &operator++() { + std::error_code EC; + It.increment(EC); + if (EC) + It = directory_iterator(); + return *this; + } + + const directory_entry &operator*() const { return *It; } + const directory_entry *operator->() const { return &*It; } + + bool operator==(const directory_iterator_error_wrapper &RHS) const { + return It == RHS.It; + } + bool operator!=(const directory_iterator_error_wrapper &RHS) const { + return !(*this == RHS); + } +}; + class FileSystem; namespace detail { @@ -274,6 +306,9 @@ virtual directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) = 0; + /// Get a directory_iterator range for \p Dir. + iterator_range dir_range(const Twine &Dir); + /// Set the working directory. This will affect all following operations on /// this file system and may propagate down for nested file systems. virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0; diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -128,6 +128,13 @@ return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); } +iterator_range +FileSystem::dir_range(const Twine &Dir) { + std::error_code EC; + return {directory_iterator_error_wrapper(dir_begin(Dir, EC), EC), + directory_iterator_error_wrapper()}; +} + std::error_code FileSystem::makeAbsolute(SmallVectorImpl &Path) const { if (llvm::sys::path::is_absolute(Path)) return {};