/// MemoryBuffer if successful, otherwise returning null.
llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
std::string *ErrorStr = nullptr,
- bool isVolatile = false);
+ bool isVolatile = false,
+ bool ShouldCloseOpenFile = true);
llvm::MemoryBuffer *getBufferForFile(StringRef Filename,
std::string *ErrorStr = nullptr);
#include "clang/Basic/FileManager.h"
#include "clang/Serialization/Module.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
/// \brief Remove the given set of modules.
void removeModules(ModuleIterator first, ModuleIterator last,
+ llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
ModuleMap *modMap);
/// \brief Add an in-memory buffer the list of known buffers
llvm::MemoryBuffer *FileManager::
getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
- bool isVolatile) {
+ bool isVolatile, bool ShouldCloseOpenFile) {
std::unique_ptr<llvm::MemoryBuffer> Result;
std::error_code ec;
/*RequiresNullTerminator=*/true, isVolatile);
if (ErrorStr)
*ErrorStr = ec.message();
- Entry->closeFile();
+ // FIXME: we need a set of APIs that can make guarantees about whether a
+ // FileEntry is open or not.
+ if (ShouldCloseOpenFile)
+ Entry->closeFile();
return Result.release();
}
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
- case HadErrors:
+ case HadErrors: {
+ llvm::SmallPtrSet<ModuleFile *, 4> LoadedSet;
+ for (const ImportedModule &IM : Loaded)
+ LoadedSet.insert(IM.Mod);
+
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ LoadedSet,
Context.getLangOpts().Modules
? &PP.getHeaderSearchInfo().getModuleMap()
: nullptr);
GlobalIndex.reset();
ModuleMgr.setGlobalIndex(nullptr);
return ReadResult;
-
+ }
case Success:
break;
}
ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
if (ec)
ErrorStr = ec.message();
- } else
- New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
+ } else {
+ // Leave the FileEntry open so if it gets read again by another
+ // ModuleManager it must be the same underlying file.
+ // FIXME: Because FileManager::getFile() doesn't guarantee that it will
+ // give us an open file, this may not be 100% reliable.
+ New->Buffer.reset(FileMgr.getBufferForFile(New->File, &ErrorStr,
+ /*IsVolatile*/false,
+ /*ShouldClose*/false));
+ }
if (!New->Buffer)
return Missing;
return NewModule? NewlyLoaded : AlreadyLoaded;
}
-static void getModuleFileAncestors(
- ModuleFile *F,
- llvm::SmallPtrSetImpl<ModuleFile *> &Ancestors) {
- Ancestors.insert(F);
- for (ModuleFile *Importer : F->ImportedBy)
- getModuleFileAncestors(Importer, Ancestors);
-}
-
-void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
- ModuleMap *modMap) {
+void ModuleManager::removeModules(
+ ModuleIterator first, ModuleIterator last,
+ llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
+ ModuleMap *modMap) {
if (first == last)
return;
// Collect the set of module file pointers that we'll be removing.
llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
- // The last module file caused the load failure, so it and its ancestors in
- // the module dependency tree will be rebuilt (or there was an error), so
- // there should be no references to them. Collect the files to remove from
- // the cache below, since rebuilding them will create new files at the old
- // locations.
- llvm::SmallPtrSet<ModuleFile *, 4> Ancestors;
- getModuleFileAncestors(*(last-1), Ancestors);
- assert(Ancestors.count(*first) && "non-dependent module loaded");
-
// Remove any references to the now-destroyed modules.
for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
Chain[i]->ImportedBy.remove_if([&](ModuleFile *MF) {
}
}
- if (Ancestors.count(*victim))
+ // Files that didn't make it through ReadASTCore successfully will be
+ // rebuilt (or there was an error). Invalidate them so that we can load the
+ // new files that will be renamed over the old ones.
+ if (LoadedSuccessfully.count(*victim) == 0)
FileMgr.invalidateCache((*victim)->File);
delete *victim;