aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Serialization/ASTReader.h13
-rw-r--r--include/clang/Serialization/GlobalModuleIndex.h96
-rw-r--r--include/clang/Serialization/ModuleManager.h73
-rw-r--r--lib/Frontend/ASTUnit.cpp1
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp1
-rw-r--r--lib/Frontend/CompilerInstance.cpp157
-rw-r--r--lib/Serialization/ASTReader.cpp95
-rw-r--r--lib/Serialization/ASTWriter.cpp2
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp237
-rw-r--r--lib/Serialization/ModuleManager.cpp116
-rw-r--r--test/Modules/Inputs/Modified/B.h3
-rw-r--r--test/Modules/Inputs/Modified/module.map5
-rw-r--r--test/Modules/modify-module.m13
13 files changed, 491 insertions, 321 deletions
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 2744865819..61a0cbebd7 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -48,6 +48,7 @@
#include <string>
#include <utility>
#include <vector>
+#include <sys/stat.h>
namespace llvm {
class MemoryBuffer;
@@ -236,6 +237,8 @@ public:
Success,
/// \brief The AST file itself appears corrupted.
Failure,
+ /// \brief The AST file was missing.
+ Missing,
/// \brief The AST file is out-of-date relative to its input files,
/// and needs to be regenerated.
OutOfDate,
@@ -949,6 +952,7 @@ private:
ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
SourceLocation ImportLoc, ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
@@ -1146,15 +1150,18 @@ public:
/// \brief The client can't handle any AST loading failures.
ARR_None = 0,
/// \brief The client can handle an AST file that cannot load because it
+ /// is missing.
+ ARR_Missing = 0x1,
+ /// \brief The client can handle an AST file that cannot load because it
/// is out-of-date relative to its input files.
- ARR_OutOfDate = 0x1,
+ ARR_OutOfDate = 0x2,
/// \brief The client can handle an AST file that cannot load because it
/// was built with a different version of Clang.
- ARR_VersionMismatch = 0x2,
+ ARR_VersionMismatch = 0x4,
/// \brief The client can handle an AST file that cannot load because it's
/// compiled configuration doesn't match that of the context it was
/// loaded into.
- ARR_ConfigurationMismatch = 0x4
+ ARR_ConfigurationMismatch = 0x8
};
/// \brief Load the AST file designated by the given file name.
diff --git a/include/clang/Serialization/GlobalModuleIndex.h b/include/clang/Serialization/GlobalModuleIndex.h
index ec8ad353e0..53f61e2d59 100644
--- a/include/clang/Serialization/GlobalModuleIndex.h
+++ b/include/clang/Serialization/GlobalModuleIndex.h
@@ -34,9 +34,44 @@ class DirectoryEntry;
class FileEntry;
class FileManager;
+namespace serialization {
+ class ModuleFile;
+};
+
using llvm::SmallVector;
using llvm::SmallVectorImpl;
using llvm::StringRef;
+using serialization::ModuleFile;
+
+/// \brief Abstract class that resolves a module file name to a ModuleFile
+/// pointer, which is used to uniquely describe a module file.
+class ModuleFileNameResolver {
+public:
+ virtual ~ModuleFileNameResolver();
+
+ /// \brief Attempt to resolve the given module file name to a specific,
+ /// already-loaded module.
+ ///
+ /// \param FileName The name of the module file.
+ ///
+ /// \param ExpectedSize The size that the module file is expected to have.
+ /// If the actual size differs, the resolver should return \c true.
+ ///
+ /// \param ExpectedModTime The modification time that the module file is
+ /// expected to have. If the actual modification time differs, the resolver
+ /// should return \c true.
+ ///
+ /// \param File Will be set to the module file if there is one, or null
+ /// otherwise.
+ ///
+ /// \returns True if a module file exists but does not meet the size/
+ /// modification time criteria, false if the module file is available or has
+ /// not yet been loaded.
+ virtual bool resolveModuleFileName(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ ModuleFile *&File) = 0;
+};
/// \brief A global index for a set of module files, providing information about
/// the identifiers within those module files.
@@ -54,6 +89,9 @@ class GlobalModuleIndex {
/// as the global module index is live.
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ /// \brief The module file name resolver.
+ ModuleFileNameResolver *Resolver;
+
/// \brief The hash table.
///
/// This pointer actually points to a IdentifierIndexTable object,
@@ -63,25 +101,39 @@ class GlobalModuleIndex {
/// \brief Information about a given module file.
struct ModuleInfo {
- ModuleInfo() : File() { }
+ ModuleInfo() : File(), Size(), ModTime() { }
+
+ /// \brief The module file, if it is known.
+ ModuleFile *File;
+
+ /// \brief The module file name.
+ std::string FileName;
+
+ /// \brief Size of the module file at the time the global index was built.
+ off_t Size;
- /// \brief The module file entry.
- const FileEntry *File;
+ /// \brief Modification time of the module file at the time the global
+ /// index was built.
+ time_t ModTime;
- /// \brief The module files on which this module directly depends.
- llvm::SmallVector<const FileEntry *, 4> Dependencies;
+ /// \brief The module IDs on which this module directly depends.
+ /// FIXME: We don't really need a vector here.
+ llvm::SmallVector<unsigned, 4> Dependencies;
+
+ /// \brief The module IDs that directly depend on this module.
+ llvm::SmallVector<unsigned, 4> ImportedBy;
};
/// \brief A mapping from module IDs to information about each module.
///
/// This vector may have gaps, if module files have been removed or have
/// been updated since the index was built. A gap is indicated by an empty
- /// \c File pointer.
+ /// file name.
llvm::SmallVector<ModuleInfo, 16> Modules;
- /// \brief Lazily-populated mapping from module file entries to their
+ /// \brief Lazily-populated mapping from module files to their
/// corresponding index into the \c Modules vector.
- llvm::DenseMap<const FileEntry *, unsigned> ModulesByFile;
+ llvm::DenseMap<ModuleFile *, unsigned> ModulesByFile;
/// \brief The number of identifier lookups we performed.
unsigned NumIdentifierLookups;
@@ -91,7 +143,7 @@ class GlobalModuleIndex {
unsigned NumIdentifierLookupHits;
/// \brief Internal constructor. Use \c readIndex() to read an index.
- explicit GlobalModuleIndex(FileManager &FileMgr, llvm::MemoryBuffer *Buffer,
+ explicit GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
llvm::BitstreamCursor Cursor);
GlobalModuleIndex(const GlobalModuleIndex &) LLVM_DELETED_FUNCTION;
@@ -115,29 +167,27 @@ public:
/// \brief Read a global index file for the given directory.
///
- /// \param FileMgr The file manager to use for reading files.
- ///
/// \param Path The path to the specific module cache where the module files
/// for the intended configuration reside.
///
/// \returns A pair containing the global module index (if it exists) and
/// the error code.
static std::pair<GlobalModuleIndex *, ErrorCode>
- readIndex(FileManager &FileMgr, StringRef Path);
+ readIndex(StringRef Path);
/// \brief Retrieve the set of modules that have up-to-date indexes.
///
/// \param ModuleFiles Will be populated with the set of module files that
/// have been indexed.
- void getKnownModules(SmallVectorImpl<const FileEntry *> &ModuleFiles);
+ void getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles);
/// \brief Retrieve the set of module files on which the given module file
/// directly depends.
- void getModuleDependencies(const FileEntry *ModuleFile,
- SmallVectorImpl<const FileEntry *> &Dependencies);
+ void getModuleDependencies(ModuleFile *File,
+ SmallVectorImpl<ModuleFile *> &Dependencies);
/// \brief A set of module files in which we found a result.
- typedef llvm::SmallPtrSet<const FileEntry *, 4> HitSet;
+ typedef llvm::SmallPtrSet<ModuleFile *, 4> HitSet;
/// \brief Look for all of the module files with information about the given
/// identifier, e.g., a global function, variable, or type with that name.
@@ -150,6 +200,20 @@ public:
/// \returns true if the identifier is known to the index, false otherwise.
bool lookupIdentifier(StringRef Name, HitSet &Hits);
+ /// \brief Set the module file name resolver.
+ void setResolver(ModuleFileNameResolver *Resolver) {
+ this->Resolver = Resolver;
+ }
+
+ /// \brief Note that additional modules have been loaded, which invalidates
+ /// the module file -> module cache.
+ void noteAdditionalModulesLoaded() {
+ ModulesByFile.clear();
+ }
+
+ /// \brief Resolve the module file for the module with the given ID.
+ ModuleFile *resolveModuleFile(unsigned ID);
+
/// \brief Print statistics to standard error.
void printStats();
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 60e3b40a7a..9b58b75ebb 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -16,17 +16,18 @@
#define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H
#include "clang/Basic/FileManager.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
-class GlobalModuleIndex;
+class ModuleMap;
namespace serialization {
/// \brief Manages the set of modules loaded by an AST reader.
-class ModuleManager {
+class ModuleManager : public ModuleFileNameResolver {
/// \brief The chain of AST files. The first entry is the one named by the
/// user, the last one is the one that doesn't depend on anything further.
SmallVector<ModuleFile *, 2> Chain;
@@ -143,6 +144,19 @@ public:
/// \brief Number of modules loaded
unsigned size() const { return Chain.size(); }
+
+ /// \brief The result of attempting to add a new module.
+ enum AddModuleResult {
+ /// \brief The module file had already been loaded.
+ AlreadyLoaded,
+ /// \brief The module file was just loaded in response to this call.
+ NewlyLoaded,
+ /// \brief The module file is missing.
+ Missing,
+ /// \brief The module file is out-of-date.
+ OutOfDate
+ };
+
/// \brief Attempts to create a new module and add it to the list of known
/// modules.
///
@@ -157,18 +171,30 @@ public:
///
/// \param Generation The generation in which this module was loaded.
///
+ /// \param ExpectedSize The expected size of the module file, used for
+ /// validation. This will be zero if unknown.
+ ///
+ /// \param ExpectedModTime The expected modification time of the module
+ /// file, used for validation. This will be zero if unknown.
+ ///
+ /// \param Module A pointer to the module file if the module was successfully
+ /// loaded.
+ ///
/// \param ErrorStr Will be set to a non-empty string if any errors occurred
/// while trying to load the module.
///
/// \return A pointer to the module that corresponds to this file name,
- /// and a boolean indicating whether the module was newly added.
- std::pair<ModuleFile *, bool>
- addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc,
- ModuleFile *ImportedBy, unsigned Generation,
- std::string &ErrorStr);
+ /// and a value indicating whether the module was loaded.
+ AddModuleResult addModule(StringRef FileName, ModuleKind Type,
+ SourceLocation ImportLoc,
+ ModuleFile *ImportedBy, unsigned Generation,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ModuleFile *&Module,
+ std::string &ErrorStr);
/// \brief Remove the given set of modules.
- void removeModules(ModuleIterator first, ModuleIterator last);
+ void removeModules(ModuleIterator first, ModuleIterator last,
+ ModuleMap *modMap);
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
@@ -200,7 +226,7 @@ public:
/// Any module that is known to both the global module index and the module
/// manager that is *not* in this set can be skipped.
void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData,
- llvm::SmallPtrSet<const FileEntry *, 4> *ModuleFilesHit = 0);
+ llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit = 0);
/// \brief Visit each of the modules with a depth-first traversal.
///
@@ -221,7 +247,34 @@ public:
void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData);
-
+
+ /// \brief Attempt to resolve the given module file name to a file entry.
+ ///
+ /// \param FileName The name of the module file.
+ ///
+ /// \param ExpectedSize The size that the module file is expected to have.
+ /// If the actual size differs, the resolver should return \c true.
+ ///
+ /// \param ExpectedModTime The modification time that the module file is
+ /// expected to have. If the actual modification time differs, the resolver
+ /// should return \c true.
+ ///
+ /// \param File Will be set to the file if there is one, or null
+ /// otherwise.
+ ///
+ /// \returns True if a file exists but does not meet the size/
+ /// modification time criteria, false if the file is either available and
+ /// suitable, or is missing.
+ bool lookupModuleFile(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ const FileEntry *&File);
+
+ virtual bool resolveModuleFileName(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ ModuleFile *&File);
+
/// \brief View the graphviz representation of the module graph.
void viewGraph();
};
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 4a956ff3ab..c1115aedbf 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -801,6 +801,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
break;
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index f414f93812..3b31bf6362 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -47,6 +47,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
return Reader.take();
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ce6572aa1b..d5c1a27ec8 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -338,6 +338,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Unrecoverable failure: don't even try to process the input file.
break;
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -945,88 +946,6 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
} else
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName);
- if (ModuleFileName.empty()) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = ModuleLoadResult();
- return LastModuleImportResult;
- }
-
- const FileEntry *ModuleFile
- = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false,
- /*CacheFailure=*/false);
- bool BuildingModule = false;
- if (!ModuleFile && Module) {
- // The module is not cached, but we have a module map from which we can
- // build the module.
-
- // Check whether there is a cycle in the module graph.
- ModuleBuildStack Path = getSourceManager().getModuleBuildStack();
- ModuleBuildStack::iterator Pos = Path.begin(), PosEnd = Path.end();
- for (; Pos != PosEnd; ++Pos) {
- if (Pos->first == ModuleName)
- break;
- }
-
- if (Pos != PosEnd) {
- SmallString<256> CyclePath;
- for (; Pos != PosEnd; ++Pos) {
- CyclePath += Pos->first;
- CyclePath += " -> ";
- }
- CyclePath += ModuleName;
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
- << ModuleName << CyclePath;
- return ModuleLoadResult();
- }
-
- // Check whether we have already attempted to build this module (but
- // failed).
- if (getPreprocessorOpts().FailedModules &&
- getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- BuildingModule = true;
- compileModule(*this, ModuleNameLoc, Module, ModuleFileName);
- ModuleFile = FileMgr->getFile(ModuleFileName, /*OpenFile=*/false,
- /*CacheFailure=*/false);
-
- if (!ModuleFile && getPreprocessorOpts().FailedModules)
- getPreprocessorOpts().FailedModules->addFailed(ModuleName);
- }
-
- if (!ModuleFile) {
- getDiagnostics().Report(ModuleNameLoc,
- BuildingModule? diag::err_module_not_built
- : diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
-
- // If there is already a module file associated with this module, make sure
- // it is the same as the module file we're looking for. Otherwise, we
- // have two module files for the same module.
- if (const FileEntry *CurModuleFile = Module? Module->getASTFile() : 0) {
- if (CurModuleFile != ModuleFile) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_file_conflict)
- << ModuleName
- << CurModuleFile->getName()
- << ModuleFile->getName();
- ModuleBuildFailed = true;
- return ModuleLoadResult();
- }
- }
-
// If we don't already have an ASTReader, create one now.
if (!ModuleManager) {
if (!hasASTContext())
@@ -1056,21 +975,53 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleManager->StartTranslationUnit(&getASTConsumer());
}
- // 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, ImportLoc,
- ARRFlags)) {
+ // Try to load the module file.
+ unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate: {
- // The module file is out-of-date. Rebuild it.
- getFileManager().invalidateCache(ModuleFile);
+ // The module file is out-of-date. Remove it, then rebuild it.
bool Existed;
llvm::sys::fs::remove(ModuleFileName, Existed);
+ }
+ // Fall through to build the module again.
+
+ case ASTReader::Missing: {
+ // The module file is (now) missing. Build it.
+
+ // If we don't have a module, we don't know how to build the module file.
+ // Complain and return.
+ if (!Module) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
+ }
+
+ // Check whether there is a cycle in the module graph.
+ ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
+ ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
+ for (; Pos != PosEnd; ++Pos) {
+ if (Pos->first == ModuleName)
+ break;
+ }
+
+ if (Pos != PosEnd) {
+ SmallString<256> CyclePath;
+ for (; Pos != PosEnd; ++Pos) {
+ CyclePath += Pos->first;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName;
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName << CyclePath;
+ return ModuleLoadResult();
+ }
// Check whether we have already attempted to build this module (but
// failed).
@@ -1083,15 +1034,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
+ // Try to compile the module.
compileModule(*this, ModuleNameLoc, Module, ModuleFileName);
- // Try loading the module again.
- ModuleFile = FileMgr->getFile(ModuleFileName, /*OpenFile=*/false,
- /*CacheFailure=*/false);
- if (!ModuleFile ||
- ModuleManager->ReadAST(ModuleFileName,
+ // Try to read the module file, now that we've compiled it.
+ ASTReader::ASTReadResult ReadResult
+ = ModuleManager->ReadAST(ModuleFileName,
serialization::MK_Module, ImportLoc,
- ASTReader::ARR_None) != ASTReader::Success) {
+ ASTReader::ARR_Missing);
+ if (ReadResult != ASTReader::Success) {
+ if (ReadResult == ASTReader::Missing) {
+ getDiagnostics().Report(ModuleNameLoc,
+ Module? diag::err_module_not_built
+ : diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ }
+
if (getPreprocessorOpts().FailedModules)
getPreprocessorOpts().FailedModules->addFailed(ModuleName);
KnownModules[Path[0].first] = 0;
@@ -1125,10 +1084,6 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
.findModule((Path[0].first->getName()));
}
- if (Module) {
- Module->setASTFile(ModuleFile);
- }
-
// Cache the result of this top-level module lookup for later.
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index cc9b5d506a..6530bae509 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1616,8 +1616,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
|| StoredTime != File->getModificationTime()
#endif
)) {
- if (Complain)
+ if (Complain) {
Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
+ }
+
IsOutOfDate = true;
}
@@ -1774,6 +1776,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// location info are setup.
SourceLocation ImportLoc =
SourceLocation::getFromRawEncoding(Record[Idx++]);
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
unsigned Length = Record[Idx++];
SmallString<128> ImportedFile(Record.begin() + Idx,
Record.begin() + Idx + Length);
@@ -1781,9 +1785,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// Load the AST file.
switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
+ StoredSize, StoredModTime,
ClientLoadCapabilities)) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
+ case Missing: return Missing;
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -2774,7 +2780,7 @@ bool ASTReader::loadGlobalIndex() {
StringRef ModuleCachePath
= getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result
- = GlobalModuleIndex::readIndex(FileMgr, ModuleCachePath);
+ = GlobalModuleIndex::readIndex(ModuleCachePath);
if (!Result.first)
return true;
@@ -2799,13 +2805,18 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
SmallVector<ImportedModule, 4> Loaded;
switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
/*ImportedBy=*/0, Loaded,
+ 0, 0,
ClientLoadCapabilities)) {
case Failure:
+ case Missing:
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
case HadErrors:
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ Context.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : 0);
// If we find that any modules are unusable, the global index is going
// to be out-of-date. Just remove it.
@@ -2923,27 +2934,54 @@ ASTReader::ReadASTCore(StringRef FileName,
SourceLocation ImportLoc,
ModuleFile *ImportedBy,
SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
unsigned ClientLoadCapabilities) {
ModuleFile *M;
- bool NewModule;
std::string ErrorStr;
- llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportLoc,
- ImportedBy, CurrentGeneration,
- ErrorStr);
-
- if (!M) {
- // We couldn't load the module.
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- return Failure;
- }
+ ModuleManager::AddModuleResult AddResult
+ = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
+ CurrentGeneration, ExpectedSize, ExpectedModTime,
+ M, ErrorStr);
- if (!NewModule) {
- // We've already loaded this module.
+ switch (AddResult) {
+ case ModuleManager::AlreadyLoaded:
return Success;
+
+ case ModuleManager::NewlyLoaded:
+ // Load module file below.
+ break;
+
+ case ModuleManager::Missing:
+ // The module file was missing; if the client handle handle, that, return
+ // it.
+ if (ClientLoadCapabilities & ARR_Missing)
+ return Missing;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
+
+ case ModuleManager::OutOfDate:
+ // We couldn't load the module file because it is out-of-date. If the
+ // client can handle out-of-date, return it.
+ if (ClientLoadCapabilities & ARR_OutOfDate)
+ return OutOfDate;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
}
+ assert(M && "Missing module file");
+
// FIXME: This seems rather a hack. Should CurrentDir be part of the
// module?
if (FileName != "-") {
@@ -2997,6 +3035,7 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
case Failure: return Failure;
+ case Missing: return Missing;
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -3467,18 +3506,22 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return true;
}
- if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
- if (CurFile != F.File) {
- if (!Diags.isDiagnosticInFlight()) {
- Diag(diag::err_module_file_conflict)
- << CurrentModule->getTopLevelModuleName()
- << CurFile->getName()
- << F.File->getName();
+ if (!ParentModule) {
+ if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
+ if (CurFile != F.File) {
+ if (!Diags.isDiagnosticInFlight()) {
+ Diag(diag::err_module_file_conflict)
+ << CurrentModule->getTopLevelModuleName()
+ << CurFile->getName()
+ << F.File->getName();
+ }
+ return true;
}
- return true;
}
+
+ CurrentModule->setASTFile(F.File);
}
- CurrentModule->setASTFile(F.File);
+
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->InferSubmodules = InferSubmodules;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 716b1fbb30..724c8cf825 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1034,6 +1034,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
AddSourceLocation((*M)->ImportLoc, Record);
+ Record.push_back((*M)->File->getSize());
+ Record.push_back((*M)->File->getModificationTime());
// FIXME: This writes the absolute path for AST files we depend on.
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index 7d34f85fd8..8b5851dbe5 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -57,6 +57,8 @@ static const char * const IndexFileName = "modules.idx";
/// \brief The global index file version.
static const unsigned CurrentVersion = 1;
+ModuleFileNameResolver::~ModuleFileNameResolver() { }
+
//----------------------------------------------------------------------------//
// Global module index reader.
//----------------------------------------------------------------------------//
@@ -115,29 +117,16 @@ public:
typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
-/// \brief Module information as it was loaded from the index file.
-struct LoadedModuleInfo {
- const FileEntry *File;
- SmallVector<unsigned, 2> Dependencies;
- SmallVector<unsigned, 2> ImportedBy;
-};
-
}
-GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr,
- llvm::MemoryBuffer *Buffer,
+GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
llvm::BitstreamCursor Cursor)
- : Buffer(Buffer), IdentifierIndex(),
+ : Buffer(Buffer), Resolver(), IdentifierIndex(),
NumIdentifierLookups(), NumIdentifierLookupHits()
{
- typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap;
- LoadedModulesMap LoadedModules;
-
// Read the global index.
- unsigned LargestID = 0;
bool InGlobalIndexBlock = false;
bool Done = false;
- bool AnyOutOfDate = false;
while (!Done) {
llvm::BitstreamEntry Entry = Cursor.advance();
@@ -185,41 +174,33 @@ GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr,
case MODULE: {
unsigned Idx = 0;
unsigned ID = Record[Idx++];
- if (ID > LargestID)
- LargestID = ID;
-
- off_t Size = Record[Idx++];
- time_t ModTime = Record[Idx++];
+
+ // Make room for this module's information.
+ if (ID == Modules.size())
+ Modules.push_back(ModuleInfo());
+ else
+ Modules.resize(ID + 1);
+
+ // Size/modification time for this module file at the time the
+ // global index was built.
+ Modules[ID].Size = Record[Idx++];
+ Modules[ID].ModTime = Record[Idx++];
// File name.
unsigned NameLen = Record[Idx++];
- llvm::SmallString<64> FileName(Record.begin() + Idx,
- Record.begin() + Idx + NameLen);
+ Modules[ID].FileName.assign(Record.begin() + Idx,
+ Record.begin() + Idx + NameLen);
Idx += NameLen;
// Dependencies
unsigned NumDeps = Record[Idx++];
- llvm::SmallVector<unsigned, 2>
- Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps);
-
- // Find the file. If we can't find it, ignore it.
- const FileEntry *File = FileMgr.getFile(FileName, /*openFile=*/false,
- /*cacheFailure=*/false);
- if (!File) {
- AnyOutOfDate = true;
- break;
- }
-
- // If the module file is newer than the index, ignore it.
- if (File->getSize() != Size || File->getModificationTime() != ModTime) {
- AnyOutOfDate = true;
- break;
- }
+ Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
+ Record.begin() + Idx,
+