When loading a module fails because it is out of date, rebuild that

module in place. <rdar://problem/10138913>

llvm-svn: 167539
This commit is contained in:
Douglas Gregor 2012-11-07 17:46:15 +00:00
parent b9db60fbce
commit 188dbef26d
8 changed files with 111 additions and 13 deletions

View File

@ -105,7 +105,10 @@ public:
std::pair<ModuleFile *, bool>
addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy,
unsigned Generation, std::string &ErrorStr);
/// \brief Remove the given set of modules.
void removeModules(ModuleIterator first, ModuleIterator last);
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);

View File

@ -762,7 +762,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Someone else is responsible for building the module. Wait for them to
// finish.
Locked.waitForUnlock();
break;
return;
}
ModuleMap &ModMap
@ -975,13 +975,36 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
}
// Try to load the module we found.
unsigned ARRFlags = ASTReader::ARR_None;
if (Module)
ARRFlags |= ASTReader::ARR_OutOfDate;
switch (ModuleManager->ReadAST(ModuleFile->getName(),
serialization::MK_Module,
ASTReader::ARR_None)) {
ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate:
case ASTReader::OutOfDate: {
// The module file is out-of-date. Rebuild it.
getFileManager().invalidateCache(ModuleFile);
bool Existed;
llvm::sys::fs::remove(ModuleFileName, Existed);
compileModule(*this, Module, ModuleFileName);
// Try loading the module again.
ModuleFile = FileMgr->getFile(ModuleFileName);
if (!ModuleFile ||
ModuleManager->ReadAST(ModuleFileName,
serialization::MK_Module,
ASTReader::ARR_None) != ASTReader::Success) {
KnownModules[Path[0].first] = 0;
return 0;
}
// Okay, we've rebuilt and now loaded the module.
break;
}
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
case ASTReader::HadErrors:

View File

@ -2675,16 +2675,21 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
// Load the core of the AST files.
unsigned NumModules = ModuleMgr.size();
llvm::SmallVector<ModuleFile *, 4> Loaded;
switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0, Loaded,
ClientLoadCapabilities)) {
case Failure: return Failure;
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
case HadErrors: return HadErrors;
case Success: break;
switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type,
/*ImportedBy=*/0, Loaded,
ClientLoadCapabilities)) {
case Failure:
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
case HadErrors:
ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
return ReadResult;
case Success:
break;
}
// Here comes stuff that we only do once the entire chain is loaded.

View File

@ -88,6 +88,45 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return std::make_pair(ModuleEntry, NewModule);
}
namespace {
/// \brief Predicate that checks whether a module file occurs within
/// the given set.
class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
public:
IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
: Removed(Removed) { }
bool operator()(ModuleFile *MF) const {
return Removed.count(MF);
}
};
}
void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
if (first == last)
return;
// Collect the set of module file pointers that we'll be removing.
llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
// Remove any references to the now-destroyed modules.
IsInModuleFileSet checkInSet(victimSet);
for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
Chain[i]->ImportedBy.remove_if(checkInSet);
}
// Delete the modules and erase them from the various structures.
for (ModuleIterator victim = first; victim != last; ++victim) {
Modules.erase((*victim)->File);
delete *victim;
}
// Remove the modules from the chain.
Chain.erase(first, last);
}
void ModuleManager::addInMemoryBuffer(StringRef FileName,
llvm::MemoryBuffer *Buffer) {

View File

@ -0,0 +1 @@
int getA();

View File

@ -0,0 +1,2 @@
#include "A.h"
int getB();

View File

@ -0,0 +1,2 @@
module A { header "A.h" }
module B { header "B.h" }

View File

@ -0,0 +1,23 @@
// Test that if we modify one of the input files used to form a
// header, that module and dependent modules get rebuilt.
// RUN: rm -rf %t
// RUN: mkdir -p %t/include
// RUN: cp %S/Inputs/Modified/A.h %t/include
// RUN: cp %S/Inputs/Modified/B.h %t/include
// RUN: cp %S/Inputs/Modified/module.map %t/include
// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
// expected-no-diagnostics
// RUN: touch %t/include/B.h
// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
// RUN: echo 'int getA(); int getA2();' > %t/include/A.h
// RUN: %clang_cc1 -fmodule-cache-path %t/cache -fmodules -I %t/include %s -verify
@__experimental_modules_import B;
int getValue() { return getA() + getB(); }