diff --git a/clang/include/clang/Basic/FileEntry.h b/clang/include/clang/Basic/FileEntry.h --- a/clang/include/clang/Basic/FileEntry.h +++ b/clang/include/clang/Basic/FileEntry.h @@ -341,6 +341,23 @@ OptionalFileEntryRefDegradesToFileEntryPtr>::value, "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable"); +inline bool operator==(const FileEntry *LHS, + const Optional &RHS) { + return LHS == (RHS ? &RHS->getFileEntry() : nullptr); +} +inline bool operator==(const Optional &LHS, + const FileEntry *RHS) { + return (LHS ? &LHS->getFileEntry() : nullptr) == RHS; +} +inline bool operator!=(const FileEntry *LHS, + const Optional &RHS) { + return !(LHS == RHS); +} +inline bool operator!=(const Optional &LHS, + const FileEntry *RHS) { + return !(LHS == RHS); +} + /// Cached information about one file (either on disk /// or in the virtual file system). /// diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -139,8 +139,9 @@ /// It is possible for this to be NULL if the ContentCache encapsulates /// an imaginary text buffer. /// - /// FIXME: Turn this into a FileEntryRef and remove Filename. - const FileEntry *OrigEntry; + /// FIXME: Make non-optional using a virtual file as needed, remove \c + /// Filename and use \c OrigEntry.getNameAsRequested() instead. + OptionalFileEntryRefDegradesToFileEntryPtr OrigEntry; /// References the file which the contents were actually loaded from. /// @@ -177,9 +178,13 @@ mutable unsigned IsBufferInvalid : 1; - ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {} + ContentCache() + : OrigEntry(None), ContentsEntry(nullptr), BufferOverridden(false), + IsFileVolatile(false), IsTransient(false), IsBufferInvalid(false) {} + + ContentCache(FileEntryRef Ent) : ContentCache(Ent, Ent) {} - ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) + ContentCache(FileEntryRef Ent, const FileEntry *contentEnt) : OrigEntry(Ent), ContentsEntry(contentEnt), BufferOverridden(false), IsFileVolatile(false), IsTransient(false), IsBufferInvalid(false) {} @@ -660,7 +665,7 @@ struct OverriddenFilesInfoTy { /// Files that have been overridden with the contents from another /// file. - llvm::DenseMap OverriddenFiles; + llvm::DenseMap OverriddenFiles; /// Files that were overridden with a memory buffer. llvm::DenseSet OverriddenFilesWithBuffer; @@ -978,8 +983,7 @@ /// /// \param NewFile the file whose contents will be used as the /// data instead of the contents of the given source file. - void overrideFileContents(const FileEntry *SourceFile, - const FileEntry *NewFile); + void overrideFileContents(const FileEntry *SourceFile, FileEntryRef NewFile); /// Returns true if the file contents have been overridden. bool isFileOverridden(const FileEntry *File) const { @@ -1044,8 +1048,8 @@ /// Returns the FileEntryRef for the provided FileID. Optional getFileEntryRefForID(FileID FID) const { - if (auto *Entry = getFileEntryForID(FID)) - return Entry->getLastRef(); + if (auto *Entry = getSLocEntryForFile(FID)) + return Entry->getFile().getContentCache().OrigEntry; return None; } 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 @@ -607,7 +607,7 @@ /// /// \returns The file entry for the module map file containing the given /// module, or nullptr if the module definition was inferred. - const FileEntry *getContainingModuleMapFile(const Module *Module) const; + Optional getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely /// identifies this module. @@ -618,7 +618,7 @@ /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). - const FileEntry *getModuleMapFileForUniquing(const Module *M) const; + Optional getModuleMapFileForUniquing(const Module *M) const; void setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap); diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -399,8 +399,7 @@ if (OverriddenFilesInfo) { // If the file contents are overridden with contents from another file, // pass that file to ContentCache. - llvm::DenseMap::iterator - overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt); + auto overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt); if (overI == OverriddenFilesInfo->OverriddenFiles.end()) new (Entry) ContentCache(FileEnt); else @@ -695,14 +694,18 @@ } void SourceManager::overrideFileContents(const FileEntry *SourceFile, - const FileEntry *NewFile) { - assert(SourceFile->getSize() == NewFile->getSize() && + FileEntryRef NewFile) { + assert(SourceFile->getSize() == NewFile.getSize() && "Different sizes, use the FileManager to create a virtual file with " "the correct size"); assert(FileInfos.count(SourceFile) == 0 && "This function should be called at the initialization stage, before " "any parsing occurs."); - getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile; + // FileEntryRef is not default-constructible. + auto Pair = getOverriddenFilesInfo().OverriddenFiles.insert( + std::make_pair(SourceFile, NewFile)); + if (!Pair.second) + Pair.first->second = NewFile; } Optional 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 @@ -423,7 +423,7 @@ // Remap files in the source manager (with other files). for (const auto &RF : InitOpts.RemappedFiles) { // Find the file that we're mapping to. - auto ToFile = FileMgr.getFile(RF.second); + Optional ToFile = FileMgr.getOptionalFileRef(RF.second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second; continue; @@ -431,7 +431,7 @@ // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = - FileMgr.getVirtualFile(RF.first, (*ToFile)->getSize(), 0); + FileMgr.getVirtualFile(RF.first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << RF.first; continue; @@ -1278,19 +1278,17 @@ Instance.getFrontendOpts().AllowPCMWithCompilerErrors; } -static const FileEntry *getPublicModuleMap(const FileEntry *File, - FileManager &FileMgr) { - StringRef Filename = llvm::sys::path::filename(File->getName()); - SmallString<128> PublicFilename(File->getDir()->getName()); +static Optional getPublicModuleMap(FileEntryRef File, + FileManager &FileMgr) { + StringRef Filename = llvm::sys::path::filename(File.getName()); + SmallString<128> PublicFilename(File.getDir().getName()); if (Filename == "module_private.map") llvm::sys::path::append(PublicFilename, "module.map"); else if (Filename == "module.private.modulemap") llvm::sys::path::append(PublicFilename, "module.modulemap"); else - return nullptr; - if (auto FE = FileMgr.getFile(PublicFilename)) - return *FE; - return nullptr; + return None; + return FileMgr.getOptionalFileRef(PublicFilename); } /// Compile a module file for the given module in a separate compiler instance, @@ -1306,19 +1304,16 @@ ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); bool Result; - if (const FileEntry *ModuleMapFile = + if (Optional ModuleMapFile = ModMap.getContainingModuleMapFile(Module)) { // Canonicalize compilation to start with the public module map. This is // vital for submodules declarations in the private module maps to be // correctly parsed when depending on a top level module in the public one. - if (const FileEntry *PublicMMFile = getPublicModuleMap( - ModuleMapFile, ImportingInstance.getFileManager())) + if (Optional PublicMMFile = getPublicModuleMap( + *ModuleMapFile, ImportingInstance.getFileManager())) ModuleMapFile = PublicMMFile; - // FIXME: Update header search to keep FileEntryRef rather than rely on - // getLastRef(). - StringRef ModuleMapFilePath = - ModuleMapFile->getLastRef().getNameAsRequested(); + StringRef ModuleMapFilePath = ModuleMapFile->getNameAsRequested(); // Use the module map where this module resides. Result = compileModuleImpl( @@ -1346,7 +1341,7 @@ [&](CompilerInstance &Instance) { std::unique_ptr ModuleMapBuffer = llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); - ModuleMapFile = Instance.getFileManager().getVirtualFile( + const FileEntry *ModuleMapFile = Instance.getFileManager().getVirtualFile( FakeModuleMapFile, InferredModuleMapContent.size(), 0); Instance.getSourceManager().overrideFileContents( ModuleMapFile, std::move(ModuleMapBuffer)); 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 @@ -170,11 +170,11 @@ } std::string HeaderSearch::getCachedModuleFileName(Module *Module) { - const FileEntry *ModuleMap = + Optional ModuleMap = getModuleMap().getModuleMapFileForUniquing(Module); // The ModuleMap maybe a nullptr, when we load a cached C++ module without // *.modulemap file. In this case, just return an empty string. - if (ModuleMap == nullptr) + if (!ModuleMap) return {}; return getCachedModuleFileName(Module->Name, ModuleMap->getName()); } @@ -211,7 +211,7 @@ } std::string HeaderSearch::getPrebuiltImplicitModuleFileName(Module *Module) { - const FileEntry *ModuleMap = + Optional ModuleMap = getModuleMap().getModuleMapFileForUniquing(Module); StringRef ModuleName = Module->Name; StringRef ModuleMapPath = ModuleMap->getName(); 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 @@ -609,7 +609,7 @@ UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - const FileEntry *UmbrellaModuleMap = + OptionalFileEntryRefDegradesToFileEntryPtr UmbrellaModuleMap = getModuleMapFileForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between @@ -1023,9 +1023,11 @@ // If we're not allowed to infer a framework module, don't. if (!canInfer) return nullptr; - } else - ModuleMapFile = getModuleMapFileForUniquing(Parent); - + } else { + OptionalFileEntryRefDegradesToFileEntryPtr ModuleMapRef = + getModuleMapFileForUniquing(Parent); + ModuleMapFile = ModuleMapRef; + } // Look for an umbrella header. SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); @@ -1277,19 +1279,21 @@ Mod->Headers[Module::HK_Excluded].push_back(std::move(Header)); } -const FileEntry * +Optional ModuleMap::getContainingModuleMapFile(const Module *Module) const { if (Module->DefinitionLoc.isInvalid()) - return nullptr; + return None; - return SourceMgr.getFileEntryForID( - SourceMgr.getFileID(Module->DefinitionLoc)); + return SourceMgr.getFileEntryRefForID( + SourceMgr.getFileID(Module->DefinitionLoc)); } -const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const { +Optional +ModuleMap::getModuleMapFileForUniquing(const Module *M) const { if (M->IsInferred) { assert(InferredModuleAllowedBy.count(M) && "missing inferred module map"); - return InferredModuleAllowedBy.find(M)->second; + // FIXME: Update InferredModuleAllowedBy to use FileEntryRef. + return InferredModuleAllowedBy.find(M)->second->getLastRef(); } return getContainingModuleMapFile(M); } 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 @@ -3919,7 +3919,8 @@ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName, F.ImportLoc); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); - const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr; + Optional ModMap = + M ? Map.getModuleMapFileForUniquing(M) : None; // Don't emit module relocation error if we have -fno-validate-pch if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation & DisableValidationForModuleKind::Module) && diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -193,13 +193,13 @@ auto *CurrentModule = ModulesToProcess.pop_back_val(); ProcessedModules.insert(CurrentModule); - auto *ModuleMapFile = + Optional ModuleMapFile = HS.getModuleMap().getModuleMapFileForUniquing(CurrentModule); if (!ModuleMapFile) { continue; } - ModuleMaps.insert(ModuleMapFile); + ModuleMaps.insert(*ModuleMapFile); for (auto *ImportedModule : (CurrentModule)->Imports) { if (!ImportedModule || diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -227,7 +227,7 @@ if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) { Preprocessor &PP = ScanInstance.getPreprocessor(); if (Module *CurrentModule = PP.getCurrentModuleImplementation()) - if (const FileEntry *CurrentModuleMap = + if (Optional CurrentModuleMap = PP.getHeaderSearchInfo() .getModuleMap() .getModuleMapFileForUniquing(CurrentModule)) @@ -406,13 +406,13 @@ MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName()); MD.IsSystem = M->IsSystem; - const FileEntry *ModuleMap = MDC.ScanInstance.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .getModuleMapFileForUniquing(M); + Optional ModuleMap = MDC.ScanInstance.getPreprocessor() + .getHeaderSearchInfo() + .getModuleMap() + .getModuleMapFileForUniquing(M); if (ModuleMap) { - StringRef Path = ModuleMap->tryGetRealPathName(); + StringRef Path = ModuleMap->getFileEntry().tryGetRealPathName(); if (Path.empty()) Path = ModuleMap->getName(); MD.ClangModuleMapFile = std::string(Path); diff --git a/clang/test/Modules/malformed.cpp b/clang/test/Modules/malformed.cpp --- a/clang/test/Modules/malformed.cpp +++ b/clang/test/Modules/malformed.cpp @@ -3,9 +3,9 @@ // // RUN: rm -rf %t // RUN: cd %S -// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="a1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-A -// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="b1.h" %s 2>&1 | FileCheck %s --check-prefix=CHECK-B -// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="c.h" malformed.cpp 2>&1 | FileCheck %s --check-prefix=CHECK-C +// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="a1.h" %s 2>&1 | sed 's:\\\\\?:/:g' | FileCheck %s --check-prefix=CHECK-A +// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="b1.h" %s 2>&1 | sed 's:\\\\\?:/:g' | FileCheck %s --check-prefix=CHECK-B +// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I Inputs/malformed -DHEADER="c.h" malformed.cpp 2>&1 | sed 's:\\\\\?:/:g' | FileCheck %s --check-prefix=CHECK-C #define STR2(x) #x #define STR(x) STR2(x) diff --git a/clang/tools/libclang/CIndexInclusionStack.cpp b/clang/tools/libclang/CIndexInclusionStack.cpp --- a/clang/tools/libclang/CIndexInclusionStack.cpp +++ b/clang/tools/libclang/CIndexInclusionStack.cpp @@ -59,8 +59,8 @@ // Callback to the client. // FIXME: We should have a function to construct CXFiles. - CB(static_cast( - const_cast(FI.getContentCache().OrigEntry)), + CB(static_cast(const_cast( + static_cast(FI.getContentCache().OrigEntry))), InclusionStack.data(), InclusionStack.size(), clientData); } }