From 7f330cdb31a4221be501d5d969f2e8a62f457e14 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 18 Mar 2015 01:42:29 +0000 Subject: [PATCH] Make module files passed to a module build via -fmodule-file= available to consumers of that module. Previously, such a file would only be available if the module happened to actually import something from that module. llvm-svn: 232583 --- clang/include/clang/Serialization/ASTBitCodes.h | 4 +++ clang/include/clang/Serialization/ModuleManager.h | 21 +++++++++++++++- clang/lib/Frontend/CompilerInstance.cpp | 13 ++++++++++ clang/lib/Serialization/ASTReader.cpp | 22 ++++++++++++++++ clang/lib/Serialization/ASTWriter.cpp | 29 +++++++++++++++------- clang/lib/Serialization/ModuleManager.cpp | 11 ++++++++ clang/test/Modules/Inputs/explicit-build/d.h | 0 .../Modules/Inputs/explicit-build/module.modulemap | 1 + clang/test/Modules/explicit-build.cpp | 13 ++++++++++ 9 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 clang/test/Modules/Inputs/explicit-build/d.h diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 1e26927..3668d4c 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -295,6 +295,10 @@ namespace clang { /// \brief Record code for the module build directory. MODULE_DIRECTORY = 16, + + /// \brief Record code for the list of other AST files made available by + /// this AST file but not actually used by it. + KNOWN_MODULE_FILES = 17, }; /// \brief Record types that occur within the input-files block diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h index 3d10fad..d20c7e2 100644 --- a/clang/include/clang/Serialization/ModuleManager.h +++ b/clang/include/clang/Serialization/ModuleManager.h @@ -35,7 +35,13 @@ class ModuleManager { /// \brief All loaded modules, indexed by name. llvm::DenseMap Modules; - + + typedef llvm::SetVector AdditionalKnownModuleFileSet; + + /// \brief Additional module files that are known but not loaded. Tracked + /// here so that we can re-export them if necessary. + AdditionalKnownModuleFileSet AdditionalKnownModuleFiles; + /// \brief FileManager that handles translating between filenames and /// FileEntry *. FileManager &FileMgr; @@ -219,6 +225,19 @@ public: /// has been "accepted", and will not (can not) be unloaded. void moduleFileAccepted(ModuleFile *MF); + /// \brief Notification from the frontend that the given module file is + /// part of this compilation (even if not imported) and, if this compilation + /// is exported, should be made available to importers of it. + bool addKnownModuleFile(StringRef FileName); + + /// \brief Get a list of additional module files that are not currently + /// loaded but are considered to be part of the current compilation. + llvm::iterator_range + getAdditionalKnownModuleFiles() { + return llvm::make_range(AdditionalKnownModuleFiles.begin(), + AdditionalKnownModuleFiles.end()); + } + /// \brief Visit each of the modules. /// /// This routine visits each of the modules, starting with the diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 2dac20b..ee8c403 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1331,6 +1331,19 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { } } RMN(*this); + // If we don't already have an ASTReader, create one now. + if (!ModuleManager) + createModuleManager(); + + // Tell the module manager about this module file. + if (getModuleManager()->getModuleManager().addKnownModuleFile(FileName)) { + getDiagnostics().Report(SourceLocation(), diag::err_module_file_not_found) + << FileName; + return false; + } + + // Build our mapping of module names to module files from this file + // and its imports. RMN.visitImport(FileName); if (RMN.Failed) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ec14eec..f4b4c4b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2462,6 +2462,9 @@ ASTReader::ReadControlBlock(ModuleFile &F, break; } + case KNOWN_MODULE_FILES: + break; + case LANGUAGE_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules. @@ -4248,6 +4251,8 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, ASTReaderListener &Listener) { // Open the AST file. + // FIXME: This allows use of the VFS; we do not allow use of the + // VFS when actually loading a module. auto Buffer = FileMgr.getBufferForFile(Filename); if (!Buffer) { return true; @@ -4418,6 +4423,20 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, break; } + case KNOWN_MODULE_FILES: { + // Known-but-not-technically-used module files are treated as imports. + if (!NeedsImports) + break; + + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + std::string Filename = ReadString(Record, Idx); + ResolveImportedPath(Filename, ModuleDir); + Listener.visitImport(Filename); + } + break; + } + default: // No other validation to perform. break; @@ -6842,6 +6861,9 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { EagerlyDeserializedDecls.clear(); PassInterestingDeclsToConsumer(); + + if (DeserializationListener) + DeserializationListener->ReaderInitialized(this); } void ASTReader::PrintStats() { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 5bf1dcd..10a52f8 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -867,6 +867,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(MODULE_NAME); RECORD(MODULE_MAP_FILE); RECORD(IMPORTS); + RECORD(KNOWN_MODULE_FILES); RECORD(LANGUAGE_OPTIONS); RECORD(TARGET_OPTIONS); RECORD(ORIGINAL_FILE); @@ -1222,20 +1223,28 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, serialization::ModuleManager &Mgr = Chain->getModuleManager(); Record.clear(); - for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end(); - M != MEnd; ++M) { + for (auto *M : Mgr) { // Skip modules that weren't directly imported. - if (!(*M)->isDirectlyImported()) + if (!M->isDirectlyImported()) continue; - 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()); - Record.push_back((*M)->Signature); - AddPath((*M)->FileName, Record); + 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()); + Record.push_back(M->Signature); + AddPath(M->FileName, Record); } Stream.EmitRecord(IMPORTS, Record); + + // Also emit a list of known module files that were not imported, + // but are made available by this module. + // FIXME: Should we also include a signature here? + Record.clear(); + for (auto *E : Mgr.getAdditionalKnownModuleFiles()) + AddPath(E->getName(), Record); + if (!Record.empty()) + Stream.EmitRecord(KNOWN_MODULE_FILES, Record); } // Language options. @@ -5655,6 +5664,8 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { Chain = Reader; + // Note, this will get called multiple times, once one the reader starts up + // and again each time it's done reading a PCH or module. FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls(); FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers(); diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index ac98ca0..b073984 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -227,6 +227,15 @@ ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = std::move(Buffer); } +bool ModuleManager::addKnownModuleFile(StringRef FileName) { + const FileEntry *File; + if (lookupModuleFile(FileName, 0, 0, File)) + return true; + if (!Modules.count(File)) + AdditionalKnownModuleFiles.insert(File); + return false; +} + ModuleManager::VisitState *ModuleManager::allocateVisitState() { // Fast path: if we have a cached state, use it. if (FirstVisitState) { @@ -263,6 +272,8 @@ void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { } void ModuleManager::moduleFileAccepted(ModuleFile *MF) { + AdditionalKnownModuleFiles.remove(MF->File); + if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) return; diff --git a/clang/test/Modules/Inputs/explicit-build/d.h b/clang/test/Modules/Inputs/explicit-build/d.h new file mode 100644 index 0000000..e69de29 diff --git a/clang/test/Modules/Inputs/explicit-build/module.modulemap b/clang/test/Modules/Inputs/explicit-build/module.modulemap index bd6ea83..992eed6 100644 --- a/clang/test/Modules/Inputs/explicit-build/module.modulemap +++ b/clang/test/Modules/Inputs/explicit-build/module.modulemap @@ -1,3 +1,4 @@ module a { header "a.h" } module b { header "b.h" export * } module c { header "c.h" export * } +module d { header "d.h" } diff --git a/clang/test/Modules/explicit-build.cpp b/clang/test/Modules/explicit-build.cpp index ff98f92..6fe9f7e 100644 --- a/clang/test/Modules/explicit-build.cpp +++ b/clang/test/Modules/explicit-build.cpp @@ -64,6 +64,19 @@ // RUN: -fmodule-file=%t/c.pcm \ // RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C +// ------------------------------- +// Check that -fmodule-file= in a module build makes the file transitively +// available even if it's not used. +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fno-implicit-modules -Rmodule-build -fno-modules-error-recovery \ +// RUN: -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-name=d -emit-module %S/Inputs/explicit-build/module.modulemap -o %t/d.pcm \ +// RUN: 2>&1 | FileCheck --check-prefix=CHECK-NO-IMPLICIT-BUILD %s --allow-empty +// +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fno-implicit-modules -Rmodule-build -fno-modules-error-recovery \ +// RUN: -I%S/Inputs/explicit-build \ +// RUN: -fmodule-file=%t/d.pcm \ +// RUN: -verify %s -DHAVE_A -DHAVE_B + #if HAVE_A #include "a.h" static_assert(a == 1, ""); -- 2.7.4