diff options
author | Ben Langmuir <blangmuir@apple.com> | 2014-08-12 16:42:33 +0000 |
---|---|---|
committer | Ben Langmuir <blangmuir@apple.com> | 2014-08-12 16:42:33 +0000 |
commit | 4b8a9e951e09dc1182e5790ccdd35b0a69c414e8 (patch) | |
tree | 4ec39ae4351dbda93d6d76a2c66391c8b24894f7 /clang/lib | |
parent | 87ecb89f3ba70798ccc9b5db365a182359183361 (diff) | |
download | bcm5719-llvm-4b8a9e951e09dc1182e5790ccdd35b0a69c414e8.tar.gz bcm5719-llvm-4b8a9e951e09dc1182e5790ccdd35b0a69c414e8.zip |
Verify all the module map files for a pcm are the same on load
We already verified the primary module map file (either the one that
defines the top-level module, or the one that allows inferring it if it
is an inferred framework module). Now we also verify any other module
map files that define submodules, such as when there is a
module.private.modulemap file.
llvm-svn: 215455
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 131 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 32 |
3 files changed, 124 insertions, 55 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 92de71d8f37..0af63e1bf44 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -797,7 +797,7 @@ void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, } const FileEntry * -ModuleMap::getContainingModuleMapFile(Module *Module) const { +ModuleMap::getContainingModuleMapFile(const Module *Module) const { if (Module->DefinitionLoc.isInvalid()) return nullptr; @@ -805,7 +805,7 @@ ModuleMap::getContainingModuleMapFile(Module *Module) const { SourceMgr.getFileID(Module->DefinitionLoc)); } -const FileEntry *ModuleMap::getModuleMapFileForUniquing(Module *M) const { +const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const { if (M->IsInferred) { assert(InferredModuleAllowedBy.count(M) && "missing inferred module map"); return InferredModuleAllowedBy.find(M)->second; @@ -1347,8 +1347,11 @@ void ModuleMapParser::parseModuleDecl() { // This module map defines a submodule. Go find the module of which it // is a submodule. ActiveModule = nullptr; + const Module *TopLevelModule = nullptr; for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) { if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) { + if (I == 0) + TopLevelModule = Next; ActiveModule = Next; continue; } @@ -1363,7 +1366,14 @@ void ModuleMapParser::parseModuleDecl() { HadError = true; return; } - } + + if (ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) { + assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) && + "submodule defined in same file as 'module *' that allowed its " + "top-level module"); + Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile); + } + } StringRef ModuleName = Id.back().first; SourceLocation ModuleNameLoc = Id.back().second; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index bc7778adc6c..1cce383f2d0 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2468,45 +2468,9 @@ ASTReader::ReadControlBlock(ModuleFile &F, break; case MODULE_MAP_FILE: - F.ModuleMapPath = Blob; - - // Try to resolve ModuleName in the current header search context and - // verify that it is found in the same module map file as we saved. If the - // top-level AST file is a main file, skip this check because there is no - // usable header search context. - assert(!F.ModuleName.empty() && - "MODULE_NAME should come before MOUDLE_MAP_FILE"); - if (F.Kind == MK_Module && - (*ModuleMgr.begin())->Kind != MK_MainFile) { - Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); - if (!M) { - assert(ImportedBy && "top-level import should be verified"); - if ((ClientLoadCapabilities & ARR_Missing) == 0) - Diag(diag::err_imported_module_not_found) - << F.ModuleName << ImportedBy->FileName; - return Missing; - } - - HeaderSearch &HS = PP.getHeaderSearchInfo(); - const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath); - const FileEntry *ModMap = - HS.getModuleMap().getModuleMapFileForUniquing(M); - if (StoredModMap == nullptr || StoredModMap != ModMap) { - assert(ModMap && "found module is missing module map file"); - assert(M->Name == F.ModuleName && "found module with different name"); - assert(ImportedBy && "top-level import should be verified"); - if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) - Diag(diag::err_imported_module_modmap_changed) - << F.ModuleName << ImportedBy->FileName - << ModMap->getName() << F.ModuleMapPath; - return OutOfDate; - } - } - - if (Listener) - Listener->ReadModuleMapFile(F.ModuleMapPath); - break; - + if (ASTReadResult Result = + ReadModuleMapFileBlock(Record, F, ImportedBy, ClientLoadCapabilities)) + return Result; case INPUT_FILE_OFFSETS: F.InputFileOffsets = (const uint32_t *)Blob.data(); F.InputFilesLoaded.resize(Record[0]); @@ -3315,6 +3279,89 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } } +ASTReader::ASTReadResult +ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, + const ModuleFile *ImportedBy, + unsigned ClientLoadCapabilities) { + unsigned Idx = 0; + F.ModuleMapPath = ReadString(Record, Idx); + + // Try to resolve ModuleName in the current header search context and + // verify that it is found in the same module map file as we saved. If the + // top-level AST file is a main file, skip this check because there is no + // usable header search context. + assert(!F.ModuleName.empty() && + "MODULE_NAME should come before MOUDLE_MAP_FILE"); + if (F.Kind == MK_Module && (*ModuleMgr.begin())->Kind != MK_MainFile) { + Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); + if (!M) { + assert(ImportedBy && "top-level import should be verified"); + if ((ClientLoadCapabilities & ARR_Missing) == 0) + Diag(diag::err_imported_module_not_found) + << F.ModuleName << ImportedBy->FileName; + return Missing; + } + + // Check the primary module map file. + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath); + const FileEntry *ModMap = Map.getModuleMapFileForUniquing(M); + if (StoredModMap == nullptr || StoredModMap != ModMap) { + assert(ModMap && "found module is missing module map file"); + assert(M->Name == F.ModuleName && "found module with different name"); + assert(ImportedBy && "top-level import should be verified"); + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_imported_module_modmap_changed) + << F.ModuleName << ImportedBy->FileName + << ModMap->getName() << F.ModuleMapPath; + return OutOfDate; + } + + llvm::SmallPtrSet<const FileEntry *, 1> AdditionalStoredMaps; + for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) { + // FIXME: we should use input files rather than storing names. + std::string Filename = ReadString(Record, Idx); + const FileEntry *F = + FileMgr.getFile(Filename, false, false); + if (F == nullptr) { + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Error("could not find file '" + Filename +"' referenced by AST file"); + return OutOfDate; + } + AdditionalStoredMaps.insert(F); + } + + // Check any additional module map files (e.g. module.private.modulemap) + // that are not in the pcm. + if (auto *AdditionalModuleMaps = Map.getAdditionalModuleMapFiles(M)) { + for (const FileEntry *ModMap : *AdditionalModuleMaps) { + // Remove files that match + // Note: SmallPtrSet::erase is really remove + if (!AdditionalStoredMaps.erase(ModMap)) { + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_module_different_modmap) + << F.ModuleName << /*new*/0 << ModMap->getName(); + return OutOfDate; + } + } + } + + // Check any additional module map files that are in the pcm, but not + // found in header search. Cases that match are already removed. + for (const FileEntry *ModMap : AdditionalStoredMaps) { + if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) + Diag(diag::err_module_different_modmap) + << F.ModuleName << /*not new*/1 << ModMap->getName(); + return OutOfDate; + } + } + + if (Listener) + Listener->ReadModuleMapFile(F.ModuleMapPath); + return Success; +} + + /// \brief Move the given method to the back of the global list of methods. static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { // Find the entry for this selector in the method pool. @@ -4136,9 +4183,11 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, case MODULE_NAME: Listener.ReadModuleName(Blob); break; - case MODULE_MAP_FILE: - Listener.ReadModuleMapFile(Blob); + case MODULE_MAP_FILE: { + unsigned Idx = 0; + Listener.ReadModuleMapFile(ReadString(Record, Idx)); break; + } case LANGUAGE_OPTIONS: if (ParseLanguageOptions(Record, false, Listener)) return true; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index dadbd12b23d..ccd57086c38 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1134,18 +1134,28 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, // Module map file if (WritingModule) { - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename - unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); + Record.clear(); + auto addModMap = [&](const FileEntry *F) { + SmallString<128> ModuleMap(F->getName()); + llvm::sys::fs::make_absolute(ModuleMap); + AddString(ModuleMap.str(), Record); + }; - const FileEntry *ModMapFile = PP.getHeaderSearchInfo().getModuleMap(). - getModuleMapFileForUniquing(WritingModule); - SmallString<128> ModuleMap(ModMapFile->getName()); - llvm::sys::fs::make_absolute(ModuleMap); - RecordData Record; - Record.push_back(MODULE_MAP_FILE); - Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str()); + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + + // Primary module map file. + addModMap(Map.getModuleMapFileForUniquing(WritingModule)); + + // Additional module map files. + if (auto *AdditionalModMaps = Map.getAdditionalModuleMapFiles(WritingModule)) { + Record.push_back(AdditionalModMaps->size()); + for (const FileEntry *F : *AdditionalModMaps) + addModMap(F); + } else { + Record.push_back(0); + } + + Stream.EmitRecord(MODULE_MAP_FILE, Record); } // Imports |