diff --git a/clang/include/clang/Basic/DirectoryEntry.h b/clang/include/clang/Basic/DirectoryEntry.h --- a/clang/include/clang/Basic/DirectoryEntry.h +++ b/clang/include/clang/Basic/DirectoryEntry.h @@ -51,7 +51,26 @@ const MapEntry &getMapEntry() const { return *ME; } DirectoryEntryRef() = delete; - DirectoryEntryRef(MapEntry &ME) : ME(&ME) {} + DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {} + + /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to + /// facilitate incremental adoption. + /// + /// The goal is to avoid code churn due to dances like the following: + /// \code + /// // Old code. + /// lvalue = rvalue; + /// + /// // Temporary code from an incremental patch. + /// lvalue = &rvalue.getDirectoryEntry(); + /// + /// // Final code. + /// lvalue = rvalue; + /// \endcode + /// + /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName + /// has been deleted, delete this implicit conversion. + operator const DirectoryEntry *() const { return &getDirEntry(); } private: friend class FileMgr::MapEntryOptionalStorage; @@ -147,4 +166,76 @@ } // end namespace optional_detail } // end namespace llvm +namespace clang { + +/// Wrapper around Optional that degrades to 'const +/// DirectoryEntry*', facilitating incremental patches to propagate +/// DirectoryEntryRef. +/// +/// This class can be used as return value or field where it's convenient for +/// an Optional to degrade to a 'const DirectoryEntry*'. The +/// purpose is to avoid code churn due to dances like the following: +/// \code +/// // Old code. +/// lvalue = rvalue; +/// +/// // Temporary code from an incremental patch. +/// Optional MaybeF = rvalue; +/// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr; +/// +/// // Final code. +/// lvalue = rvalue; +/// \endcode +/// +/// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef +/// and DirectoryEntry::getName have been deleted, delete this class and +/// replace instances with Optional. +class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr + : public Optional { +public: + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default; + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( + const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & + operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & + operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; + + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {} + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref) + : Optional(Ref) {} + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional MaybeRef) + : Optional(MaybeRef) {} + + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) { + Optional::operator=(None); + return *this; + } + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) { + Optional::operator=(Ref); + return *this; + } + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & + operator=(Optional MaybeRef) { + Optional::operator=(MaybeRef); + return *this; + } + + /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and + /// DirectoryEntry::getName have been deleted, delete this class and replace + /// instances with Optional + operator const DirectoryEntry *() const { + return hasValue() ? &getValue().getDirEntry() : nullptr; + } +}; + +static_assert(std::is_trivially_copyable< + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value, + "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be " + "trivially copyable"); + +} // end namespace clang + #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -133,7 +133,9 @@ std::string PresumedModuleMapFile; /// The umbrella header or directory. - llvm::PointerUnion Umbrella; + llvm::PointerUnion + Umbrella; /// The module signature. ASTFileSignature Signature; @@ -188,18 +190,18 @@ /// file. struct Header { std::string NameAsWritten; - const FileEntry *Entry; + OptionalFileEntryRefDegradesToFileEntryPtr Entry; - explicit operator bool() { return Entry; } + explicit operator bool() { return Entry != None; } }; /// Information about a directory name as found in the module map /// file. struct DirectoryName { std::string NameAsWritten; - const DirectoryEntry *Entry; + OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr Entry; - explicit operator bool() { return Entry; } + explicit operator bool() { return Entry != None; } }; /// The headers that are part of this module. @@ -544,15 +546,15 @@ /// Retrieve the header that serves as the umbrella header for this /// module. Header getUmbrellaHeader() const { - if (auto *FE = Umbrella.dyn_cast()) - return Header{UmbrellaAsWritten, FE}; + if (auto *ME = Umbrella.dyn_cast()) + return Header{UmbrellaAsWritten, FileEntryRef(*ME)}; return Header{}; } /// Determine whether this module has an umbrella directory that is /// not based on an umbrella header. bool hasUmbrellaDir() const { - return Umbrella && Umbrella.is(); + return Umbrella && Umbrella.is(); } /// Add a top-level header associated with this module. diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_LEX_MODULEMAP_H #define LLVM_CLANG_LEX_MODULEMAP_H +#include "clang/Basic/FileEntry.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" @@ -37,7 +38,6 @@ class DiagnosticsEngine; class DirectoryEntry; -class FileEntry; class FileManager; class HeaderSearch; class SourceManager; @@ -648,12 +648,12 @@ /// Sets the umbrella header of the given module to the given /// header. - void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, + void setUmbrellaHeader(Module *Mod, FileEntryRef UmbrellaHeader, Twine NameAsWritten); /// Sets the umbrella directory of the given module to the given /// directory. - void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, + void setUmbrellaDir(Module *Mod, DirectoryEntryRef UmbrellaDir, Twine NameAsWritten); /// Adds this header to the given module. diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -247,7 +247,10 @@ if (Header U = getUmbrellaHeader()) return {"", U.Entry->getDir()}; - return {UmbrellaAsWritten, Umbrella.dyn_cast()}; + if (auto *ME = Umbrella.dyn_cast()) + return {UmbrellaAsWritten, DirectoryEntryRef(*ME)}; + + return {"", None}; } void Module::addTopHeader(const FileEntry *File) { 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 @@ -304,7 +304,7 @@ << Name; continue; } - Headers.push_back({std::string(Name), &FE->getFileEntry()}); + Headers.push_back({std::string(Name), *FE}); } HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers); 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 @@ -300,7 +300,7 @@ // supplied by Clang. Find that builtin header. SmallString<128> Path; llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName); - auto File = SourceMgr.getFileManager().getFile(Path); + auto File = SourceMgr.getFileManager().getOptionalFileRef(Path); if (!File) return false; @@ -1012,7 +1012,7 @@ // Look for an umbrella header. SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h"); - auto UmbrellaHeader = FileMgr.getFile(UmbrellaName); + auto UmbrellaHeader = FileMgr.getOptionalFileRef(UmbrellaName); // FIXME: If there's no umbrella header, we could probably scan the // framework to load *everything*. But, it's not clear that this is a good @@ -1121,21 +1121,21 @@ return Result; } -void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader, +void ModuleMap::setUmbrellaHeader(Module *Mod, FileEntryRef UmbrellaHeader, Twine NameAsWritten) { Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader)); - Mod->Umbrella = UmbrellaHeader; + Mod->Umbrella = &UmbrellaHeader.getMapEntry(); Mod->UmbrellaAsWritten = NameAsWritten.str(); - UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; + UmbrellaDirs[UmbrellaHeader.getDir()] = Mod; // Notify callbacks that we just added a new header. for (const auto &Cb : Callbacks) Cb->moduleMapAddUmbrellaHeader(&SourceMgr.getFileManager(), UmbrellaHeader); } -void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir, +void ModuleMap::setUmbrellaDir(Module *Mod, DirectoryEntryRef UmbrellaDir, Twine NameAsWritten) { - Mod->Umbrella = UmbrellaDir; + Mod->Umbrella = &UmbrellaDir.getMapEntry(); Mod->UmbrellaAsWritten = NameAsWritten.str(); UmbrellaDirs[UmbrellaDir] = Mod; } @@ -2416,15 +2416,15 @@ } // Look for this file. - const DirectoryEntry *Dir = nullptr; + Optional Dir; if (llvm::sys::path::is_absolute(DirName)) { - if (auto D = SourceMgr.getFileManager().getDirectory(DirName)) + if (auto D = SourceMgr.getFileManager().getOptionalDirectoryRef(DirName)) Dir = *D; } else { SmallString<128> PathName; PathName = Directory->getName(); llvm::sys::path::append(PathName, DirName); - if (auto D = SourceMgr.getFileManager().getDirectory(PathName)) + if (auto D = SourceMgr.getFileManager().getOptionalDirectoryRef(PathName)) Dir = *D; } @@ -2445,7 +2445,7 @@ SourceMgr.getFileManager().getVirtualFileSystem(); for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E; I != E && !EC; I.increment(EC)) { - if (auto FE = SourceMgr.getFileManager().getFile(I->path())) { + if (auto FE = SourceMgr.getFileManager().getOptionalFileRef(I->path())) { Module::Header Header = {std::string(I->path()), *FE}; Headers.push_back(std::move(Header)); } @@ -2459,7 +2459,7 @@ return; } - if (Module *OwningModule = Map.UmbrellaDirs[Dir]) { + if (Module *OwningModule = Map.UmbrellaDirs[*Dir]) { Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) << OwningModule->getFullModuleName(); HadError = true; @@ -2467,7 +2467,7 @@ } // Record this umbrella directory. - Map.setUmbrellaDir(ActiveModule, Dir, DirName); + Map.setUmbrellaDir(ActiveModule, *Dir, DirName); } /// Parse a module export declaration. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1915,7 +1915,8 @@ // FIXME: This is not always the right filename-as-written, but we're not // going to use this information to rebuild the module, so it doesn't make // a lot of difference. - Module::Header H = {std::string(key.Filename), *FileMgr.getFile(Filename)}; + Module::Header H = {std::string(key.Filename), + *FileMgr.getOptionalFileRef(Filename)}; ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true); HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader); } @@ -5564,7 +5565,7 @@ case SUBMODULE_UMBRELLA_HEADER: { std::string Filename = std::string(Blob); ResolveImportedPath(F, Filename); - if (auto Umbrella = PP.getFileManager().getFile(Filename)) { + if (auto Umbrella = PP.getFileManager().getOptionalFileRef(Filename)) { if (!CurrentModule->getUmbrellaHeader()) ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob); else if (CurrentModule->getUmbrellaHeader().Entry != *Umbrella) { @@ -5597,7 +5598,8 @@ case SUBMODULE_UMBRELLA_DIR: { std::string Dirname = std::string(Blob); ResolveImportedPath(F, Dirname); - if (auto Umbrella = PP.getFileManager().getDirectory(Dirname)) { + if (auto Umbrella = + PP.getFileManager().getOptionalDirectoryRef(Dirname)) { if (!CurrentModule->getUmbrellaDir()) ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob); else if (CurrentModule->getUmbrellaDir().Entry != *Umbrella) {