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
This commit is contained in:
parent
59aca19708
commit
7f330cdb31
|
@ -295,6 +295,10 @@ namespace clang {
|
||||||
|
|
||||||
/// \brief Record code for the module build directory.
|
/// \brief Record code for the module build directory.
|
||||||
MODULE_DIRECTORY = 16,
|
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
|
/// \brief Record types that occur within the input-files block
|
||||||
|
|
|
@ -36,6 +36,12 @@ class ModuleManager {
|
||||||
/// \brief All loaded modules, indexed by name.
|
/// \brief All loaded modules, indexed by name.
|
||||||
llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
|
llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
|
||||||
|
|
||||||
|
typedef llvm::SetVector<const FileEntry *> 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
|
/// \brief FileManager that handles translating between filenames and
|
||||||
/// FileEntry *.
|
/// FileEntry *.
|
||||||
FileManager &FileMgr;
|
FileManager &FileMgr;
|
||||||
|
@ -219,6 +225,19 @@ public:
|
||||||
/// has been "accepted", and will not (can not) be unloaded.
|
/// has been "accepted", and will not (can not) be unloaded.
|
||||||
void moduleFileAccepted(ModuleFile *MF);
|
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<AdditionalKnownModuleFileSet::const_iterator>
|
||||||
|
getAdditionalKnownModuleFiles() {
|
||||||
|
return llvm::make_range(AdditionalKnownModuleFiles.begin(),
|
||||||
|
AdditionalKnownModuleFiles.end());
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Visit each of the modules.
|
/// \brief Visit each of the modules.
|
||||||
///
|
///
|
||||||
/// This routine visits each of the modules, starting with the
|
/// This routine visits each of the modules, starting with the
|
||||||
|
|
|
@ -1331,6 +1331,19 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
|
||||||
}
|
}
|
||||||
} RMN(*this);
|
} 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);
|
RMN.visitImport(FileName);
|
||||||
|
|
||||||
if (RMN.Failed)
|
if (RMN.Failed)
|
||||||
|
|
|
@ -2462,6 +2462,9 @@ ASTReader::ReadControlBlock(ModuleFile &F,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case KNOWN_MODULE_FILES:
|
||||||
|
break;
|
||||||
|
|
||||||
case LANGUAGE_OPTIONS: {
|
case LANGUAGE_OPTIONS: {
|
||||||
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
|
bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
|
||||||
// FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
|
// FIXME: The &F == *ModuleMgr.begin() check is wrong for modules.
|
||||||
|
@ -4248,6 +4251,8 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
|
||||||
FileManager &FileMgr,
|
FileManager &FileMgr,
|
||||||
ASTReaderListener &Listener) {
|
ASTReaderListener &Listener) {
|
||||||
// Open the AST file.
|
// 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);
|
auto Buffer = FileMgr.getBufferForFile(Filename);
|
||||||
if (!Buffer) {
|
if (!Buffer) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -4418,6 +4423,20 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
|
||||||
break;
|
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:
|
default:
|
||||||
// No other validation to perform.
|
// No other validation to perform.
|
||||||
break;
|
break;
|
||||||
|
@ -6842,6 +6861,9 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
|
||||||
EagerlyDeserializedDecls.clear();
|
EagerlyDeserializedDecls.clear();
|
||||||
|
|
||||||
PassInterestingDeclsToConsumer();
|
PassInterestingDeclsToConsumer();
|
||||||
|
|
||||||
|
if (DeserializationListener)
|
||||||
|
DeserializationListener->ReaderInitialized(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTReader::PrintStats() {
|
void ASTReader::PrintStats() {
|
||||||
|
|
|
@ -867,6 +867,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
||||||
RECORD(MODULE_NAME);
|
RECORD(MODULE_NAME);
|
||||||
RECORD(MODULE_MAP_FILE);
|
RECORD(MODULE_MAP_FILE);
|
||||||
RECORD(IMPORTS);
|
RECORD(IMPORTS);
|
||||||
|
RECORD(KNOWN_MODULE_FILES);
|
||||||
RECORD(LANGUAGE_OPTIONS);
|
RECORD(LANGUAGE_OPTIONS);
|
||||||
RECORD(TARGET_OPTIONS);
|
RECORD(TARGET_OPTIONS);
|
||||||
RECORD(ORIGINAL_FILE);
|
RECORD(ORIGINAL_FILE);
|
||||||
|
@ -1222,20 +1223,28 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
|
||||||
serialization::ModuleManager &Mgr = Chain->getModuleManager();
|
serialization::ModuleManager &Mgr = Chain->getModuleManager();
|
||||||
Record.clear();
|
Record.clear();
|
||||||
|
|
||||||
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
|
for (auto *M : Mgr) {
|
||||||
M != MEnd; ++M) {
|
|
||||||
// Skip modules that weren't directly imported.
|
// Skip modules that weren't directly imported.
|
||||||
if (!(*M)->isDirectlyImported())
|
if (!M->isDirectlyImported())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
|
Record.push_back((unsigned)M->Kind); // FIXME: Stable encoding
|
||||||
AddSourceLocation((*M)->ImportLoc, Record);
|
AddSourceLocation(M->ImportLoc, Record);
|
||||||
Record.push_back((*M)->File->getSize());
|
Record.push_back(M->File->getSize());
|
||||||
Record.push_back((*M)->File->getModificationTime());
|
Record.push_back(M->File->getModificationTime());
|
||||||
Record.push_back((*M)->Signature);
|
Record.push_back(M->Signature);
|
||||||
AddPath((*M)->FileName, Record);
|
AddPath(M->FileName, Record);
|
||||||
}
|
}
|
||||||
Stream.EmitRecord(IMPORTS, 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.
|
// Language options.
|
||||||
|
@ -5655,6 +5664,8 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
|
||||||
|
|
||||||
Chain = 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();
|
FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls();
|
||||||
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
|
FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes();
|
||||||
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
|
FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers();
|
||||||
|
|
|
@ -227,6 +227,15 @@ ModuleManager::addInMemoryBuffer(StringRef FileName,
|
||||||
InMemoryBuffers[Entry] = std::move(Buffer);
|
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() {
|
ModuleManager::VisitState *ModuleManager::allocateVisitState() {
|
||||||
// Fast path: if we have a cached state, use it.
|
// Fast path: if we have a cached state, use it.
|
||||||
if (FirstVisitState) {
|
if (FirstVisitState) {
|
||||||
|
@ -263,6 +272,8 @@ void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
|
void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
|
||||||
|
AdditionalKnownModuleFiles.remove(MF->File);
|
||||||
|
|
||||||
if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
|
if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
module a { header "a.h" }
|
module a { header "a.h" }
|
||||||
module b { header "b.h" export * }
|
module b { header "b.h" export * }
|
||||||
module c { header "c.h" export * }
|
module c { header "c.h" export * }
|
||||||
|
module d { header "d.h" }
|
||||||
|
|
|
@ -64,6 +64,19 @@
|
||||||
// RUN: -fmodule-file=%t/c.pcm \
|
// RUN: -fmodule-file=%t/c.pcm \
|
||||||
// RUN: -verify %s -DHAVE_A -DHAVE_B -DHAVE_C
|
// 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
|
#if HAVE_A
|
||||||
#include "a.h"
|
#include "a.h"
|
||||||
static_assert(a == 1, "");
|
static_assert(a == 1, "");
|
||||||
|
|
Loading…
Reference in New Issue