aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Serialization/ModuleManager.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
commitb60736ec1405bb0a8dd40989f67ef4c93da068ab (patch)
tree5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /clang/lib/Serialization/ModuleManager.cpp
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Diffstat (limited to 'clang/lib/Serialization/ModuleManager.cpp')
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp61
1 files changed, 41 insertions, 20 deletions
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index a42ed2f3c179..40ffa6cfee8f 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -112,7 +112,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Look for the file entry. This only fails if the expected size or
// modification time differ.
- const FileEntry *Entry;
+ OptionalFileEntryRefDegradesToFileEntryPtr Entry;
if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) {
// If we're not expecting to pull this file out of the module cache, it
// might have a different mtime due to being moved across filesystems in
@@ -132,15 +132,38 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return Missing;
}
+ // The ModuleManager's use of FileEntry nodes as the keys for its map of
+ // loaded modules is less than ideal. Uniqueness for FileEntry nodes is
+ // maintained by FileManager, which in turn uses inode numbers on hosts
+ // that support that. When coupled with the module cache's proclivity for
+ // turning over and deleting stale PCMs, this means entries for different
+ // module files can wind up reusing the same underlying inode. When this
+ // happens, subsequent accesses to the Modules map will disagree on the
+ // ModuleFile associated with a given file. In general, it is not sufficient
+ // to resolve this conundrum with a type like FileEntryRef that stores the
+ // name of the FileEntry node on first access because of path canonicalization
+ // issues. However, the paths constructed for implicit module builds are
+ // fully under Clang's control. We *can*, therefore, rely on their structure
+ // being consistent across operating systems and across subsequent accesses
+ // to the Modules map.
+ auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
+ const FileEntry *Entry) -> bool {
+ if (Kind != MK_ImplicitModule)
+ return true;
+ return Entry->getName() == MF->FileName;
+ };
+
// Check whether we already loaded this module, before
if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
- // Check the stored signature.
- if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
- return OutOfDate;
-
- Module = ModuleEntry;
- updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
- return AlreadyLoaded;
+ if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) {
+ // Check the stored signature.
+ if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
+ return OutOfDate;
+
+ Module = ModuleEntry;
+ updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
+ return AlreadyLoaded;
+ }
}
// Allocate a new module.
@@ -265,7 +288,7 @@ void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
if (modMap) {
StringRef ModuleName = victim->ModuleName;
if (Module *mod = modMap->findModule(ModuleName)) {
- mod->setASTFile(nullptr);
+ mod->setASTFile(None);
}
}
}
@@ -435,23 +458,21 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
returnVisitState(State);
}
-bool ModuleManager::lookupModuleFile(StringRef FileName,
- off_t ExpectedSize,
+bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
time_t ExpectedModTime,
- const FileEntry *&File) {
- if (FileName == "-") {
- File = nullptr;
+ Optional<FileEntryRef> &File) {
+ File = None;
+ if (FileName == "-")
return false;
- }
// Open the file immediately to ensure there is no race between stat'ing and
// opening the file.
- auto FileOrErr = FileMgr.getFile(FileName, /*OpenFile=*/true,
- /*CacheFailure=*/false);
- if (!FileOrErr) {
- File = nullptr;
+ Optional<FileEntryRef> FileOrErr =
+ expectedToOptional(FileMgr.getFileRef(FileName, /*OpenFile=*/true,
+ /*CacheFailure=*/false));
+ if (!FileOrErr)
return false;
- }
+
File = *FileOrErr;
if ((ExpectedSize && ExpectedSize != File->getSize()) ||