aboutsummaryrefslogtreecommitdiff
path: root/lib/Serialization
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-11-30 17:33:56 +0000
committerDouglas Gregor <dgregor@apple.com>2011-11-30 17:33:56 +0000
commit392ed2b717d86ebdd202cb9bb58d18d8b3b4cd87 (patch)
treebcb3eaee26ddf777965589a13e04aafe08235bc4 /lib/Serialization
parentd699ade396154238d2fa89bb09fdcfb79e5587d2 (diff)
Implement (de-)serialization of the description of a module and its
submodules. This information will eventually be used for name hiding when dealing with submodules. For now, we only use it to ensure that the module "key" returned when loading a module will always be a module (rather than occasionally being a FileEntry). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145497 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Serialization')
-rw-r--r--lib/Serialization/ASTReader.cpp124
-rw-r--r--lib/Serialization/ASTWriter.cpp85
2 files changed, 208 insertions, 1 deletions
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 2569e225b5..af12bf39fa 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1705,6 +1705,26 @@ ASTReader::ReadASTBlock(Module &F) {
return IgnorePCH;
}
break;
+
+ case SUBMODULE_BLOCK_ID:
+ switch (ReadSubmoduleBlock(F)) {
+ case Success:
+ break;
+
+ case Failure:
+ Error("malformed submodule block in AST file");
+ return Failure;
+
+ case IgnorePCH:
+ return IgnorePCH;
+ }
+ break;
+
+ default:
+ if (!Stream.SkipBlock())
+ break;
+ Error("malformed block record in AST file");
+ return Failure;
}
continue;
}
@@ -2800,6 +2820,110 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
return std::string();
}
+ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(Module &F) {
+ // Enter the submodule block.
+ if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
+ Error("malformed submodule block record in AST file");
+ return Failure;
+ }
+
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ ModuleMap::Module *CurrentModule = 0;
+ RecordData Record;
+ while (true) {
+ unsigned Code = F.Stream.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (F.Stream.ReadBlockEnd()) {
+ Error("error at end of submodule block in AST file");
+ return Failure;
+ }
+ return Success;
+ }
+
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ F.Stream.ReadSubBlockID();
+ if (F.Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::DEFINE_ABBREV) {
+ F.Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ const char *BlobStart;
+ unsigned BlobLen;
+ Record.clear();
+ switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case SUBMODULE_DEFINITION: {
+ StringRef Name(BlobStart, BlobLen);
+ unsigned Parent = Record[0];
+ bool IsFramework = Record[1];
+ bool IsExplicit = Record[2];
+
+ ModuleMap::Module *ParentModule = 0;
+ if (Parent) {
+ if (Parent > F.Submodules.size()) {
+ Error("malformed submodule parent entry");
+ return Failure;
+ }
+
+ ParentModule = F.Submodules[Parent - 1];
+ }
+
+ // Retrieve this (sub)module from the module map, creating it if
+ // necessary.
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ IsFramework,
+ IsExplicit).first;
+ F.Submodules.push_back(CurrentModule);
+ break;
+ }
+
+ case SUBMODULE_UMBRELLA: {
+ if (!CurrentModule)
+ break;
+
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (!CurrentModule->UmbrellaHeader)
+ CurrentModule->UmbrellaHeader = Umbrella;
+ else if (CurrentModule->UmbrellaHeader != Umbrella) {
+ Error("mismatched umbrella headers in submodule");
+ return Failure;
+ }
+ }
+ break;
+ }
+
+ case SUBMODULE_HEADER: {
+ if (!CurrentModule)
+ break;
+
+ // FIXME: Be more lazy about this!
+ StringRef FileName(BlobStart, BlobLen);
+ if (const FileEntry *File = PP.getFileManager().getFile(FileName)) {
+ if (std::find(CurrentModule->Headers.begin(),
+ CurrentModule->Headers.end(),
+ File) == CurrentModule->Headers.end())
+ CurrentModule->Headers.push_back(File);
+ }
+ break;
+ }
+ }
+ }
+
+ return Success;
+}
+
/// \brief Parse the record that corresponds to a LangOptions data
/// structure.
///
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index e225103f72..cf4ea41dd5 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1845,6 +1845,88 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) {
}
}
+void ASTWriter::WriteSubmodules(ModuleMap::Module *WritingModule) {
+ // Enter the submodule description block.
+ Stream.EnterSubblock(SUBMODULE_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
+
+ // Write the abbreviations needed for the submodules block.
+ using namespace llvm;
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_DEFINITION));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Parent
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsExplicit
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned UmbrellaAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_HEADER));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write all of the submodules.
+ unsigned SubmoduleID = 1;
+ std::queue<ModuleMap::Module *> Q;
+ Q.push(WritingModule);
+ RecordData Record;
+ while (!Q.empty()) {
+ ModuleMap::Module *Mod = Q.front();
+ Q.pop();
+ SubmoduleIDs[Mod] = SubmoduleID++;
+
+ // Emit the definition of the block.
+ Record.clear();
+ Record.push_back(SUBMODULE_DEFINITION);
+ if (Mod->Parent) {
+ assert(SubmoduleIDs[Mod->Parent] && "Submodule parent not written?");
+ Record.push_back(SubmoduleIDs[Mod->Parent]);
+ } else {
+ Record.push_back(0);
+ }
+ Record.push_back(Mod->IsFramework);
+ Record.push_back(Mod->IsExplicit);
+ Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
+
+ // Emit the umbrella header, if there is one.
+ if (Mod->UmbrellaHeader) {
+ Record.clear();
+ Record.push_back(SUBMODULE_UMBRELLA);
+ Stream.EmitRecordWithBlob(UmbrellaAbbrev, Record,
+ Mod->UmbrellaHeader->getName());
+ }
+
+ // Emit the headers.
+ for (unsigned I = 0, N = Mod->Headers.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_HEADER);
+ Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
+ Mod->Headers[I]->getName());
+ }
+
+ // Queue up the submodules of this module.
+ llvm::SmallVector<StringRef, 2> SubModules;
+
+ // Sort the submodules first, so we get a predictable ordering in the AST
+ // file.
+ for (llvm::StringMap<ModuleMap::Module *>::iterator
+ Sub = Mod->SubModules.begin(),
+ SubEnd = Mod->SubModules.end();
+ Sub != SubEnd; ++Sub)
+ SubModules.push_back(Sub->getKey());
+ llvm::array_pod_sort(SubModules.begin(), SubModules.end());
+
+ for (unsigned I = 0, N = SubModules.size(); I != N; ++I)
+ Q.push(Mod->SubModules[SubModules[I]]);
+ }
+
+ Stream.ExitBlock();
+}
+
void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
RecordData Record;
for (DiagnosticsEngine::DiagStatePointsTy::const_iterator
@@ -3086,7 +3168,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
-
+ if (WritingModule)
+ WriteSubmodules(WritingModule);
WritePreprocessor(PP, WritingModule != 0);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);