From 188dbef26df3901195869ff19273323d657e995f Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 7 Nov 2012 17:46:15 +0000 Subject: [PATCH] When loading a module fails because it is out of date, rebuild that module in place. llvm-svn: 167539 --- clang/include/clang/Serialization/ModuleManager.h | 5 ++- clang/lib/Frontend/CompilerInstance.cpp | 29 +++++++++++++++-- clang/lib/Serialization/ASTReader.cpp | 23 +++++++------ clang/lib/Serialization/ModuleManager.cpp | 39 +++++++++++++++++++++++ clang/test/Modules/Inputs/Modified/A.h | 1 + clang/test/Modules/Inputs/Modified/B.h | 2 ++ clang/test/Modules/Inputs/Modified/module.map | 2 ++ clang/test/Modules/modify-module.m | 23 +++++++++++++ 8 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 clang/test/Modules/Inputs/Modified/A.h create mode 100644 clang/test/Modules/Inputs/Modified/B.h create mode 100644 clang/test/Modules/Inputs/Modified/module.map create mode 100644 clang/test/Modules/modify-module.m diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h index 2233eaf..6dcaa21 100644 --- a/clang/include/clang/Serialization/ModuleManager.h +++ b/clang/include/clang/Serialization/ModuleManager.h @@ -105,7 +105,10 @@ public: std::pair 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); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index b858322..576ca94 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -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: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fad0fe1..0f3e553 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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 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. diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index c46e9f0..efe4421 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -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 { + llvm::SmallPtrSet &Removed; + + public: + IsInModuleFileSet(llvm::SmallPtrSet &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 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) { diff --git a/clang/test/Modules/Inputs/Modified/A.h b/clang/test/Modules/Inputs/Modified/A.h new file mode 100644 index 0000000..ff833c7 --- /dev/null +++ b/clang/test/Modules/Inputs/Modified/A.h @@ -0,0 +1 @@ +int getA(); diff --git a/clang/test/Modules/Inputs/Modified/B.h b/clang/test/Modules/Inputs/Modified/B.h new file mode 100644 index 0000000..d1c8bb5 --- /dev/null +++ b/clang/test/Modules/Inputs/Modified/B.h @@ -0,0 +1,2 @@ +#include "A.h" +int getB(); diff --git a/clang/test/Modules/Inputs/Modified/module.map b/clang/test/Modules/Inputs/Modified/module.map new file mode 100644 index 0000000..d9aed01 --- /dev/null +++ b/clang/test/Modules/Inputs/Modified/module.map @@ -0,0 +1,2 @@ +module A { header "A.h" } +module B { header "B.h" } diff --git a/clang/test/Modules/modify-module.m b/clang/test/Modules/modify-module.m new file mode 100644 index 0000000..b630ac1 --- /dev/null +++ b/clang/test/Modules/modify-module.m @@ -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(); } + + + + + -- 2.7.4