summaryrefslogtreecommitdiffstats
path: root/clang/lib
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
commit69021974073fddaf7ec7345819e46f16e5dcdcde (patch)
tree27e084afc851de9172d6ac662476aafa0095b6d4 /clang/lib
parent9d1eee9e2a82ccd296016290d47f918346d52a58 (diff)
downloadbcm5719-llvm-69021974073fddaf7ec7345819e46f16e5dcdcde.tar.gz
bcm5719-llvm-69021974073fddaf7ec7345819e46f16e5dcdcde.zip
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). llvm-svn: 145497
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp60
-rw-r--r--clang/lib/Lex/ModuleMap.cpp17
-rw-r--r--clang/lib/Serialization/ASTReader.cpp124
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp85
4 files changed, 259 insertions, 27 deletions
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 66b381e522e..cb66aadfa99 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1074,7 +1074,7 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
// This one-element cache is important to eliminate redundant diagnostics
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc)
- return LastModuleImportResult.getOpaqueValue();
+ return LastModuleImportResult;
// Determine what file we're searching from.
SourceManager &SourceMgr = getSourceManager();
@@ -1091,8 +1091,9 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
const FileEntry *ModuleFile = 0;
// If we don't already have information on this module, load the module now.
- KnownModule &Known = KnownModules[Path[0].first];
- if (Known.isNull()) {
+ llvm::DenseMap<const IdentifierInfo *, ModuleMap::Module *>::iterator Known
+ = KnownModules.find(Path[0].first);
+ if (Known == KnownModules.end()) {
// Search for a module with the given name.
std::string ModuleFileName;
ModuleFile
@@ -1173,39 +1174,49 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
case ASTReader::IgnorePCH:
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
+ KnownModules[Path[0].first] = 0;
return 0;
case ASTReader::Failure:
- // Already complained.
+ // Already complained, but note now that we failed.
+ KnownModules[Path[0].first] = 0;
return 0;
}
- if (Module)
- Known = Module;
- else
- Known = ModuleFile;
+ if (!Module) {
+ // If we loaded the module directly, without finding a module map first,
+ // we'll have loaded the module's information from the module itself.
+ Module = PP->getHeaderSearchInfo().getModuleMap()
+ .findModule((Path[0].first->getName()));
+ }
+
+ // Cache the result of this top-level module lookup for later.
+ Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
} else {
- Module = Known.dyn_cast<ModuleMap::Module *>();
+ // Retrieve the cached top-level module.
+ Module = Known->second;
}
+ // If we never found the module, fail.
+ if (!Module)
+ return 0;
+
// Verify that the rest of the module path actually corresponds to
// a submodule.
- ModuleMap::Module *Sub = 0;
- if (Module && Path.size() > 1) {
- Sub = Module;
+ if (Path.size() > 1) {
for (unsigned I = 1, N = Path.size(); I != N; ++I) {
StringRef Name = Path[I].first->getName();
llvm::StringMap<ModuleMap::Module *>::iterator Pos
- = Sub->SubModules.find(Name);
+ = Module->SubModules.find(Name);
- if (Pos == Sub->SubModules.end()) {
+ if (Pos == Module->SubModules.end()) {
// Attempt to perform typo correction to find a module name that works.
llvm::SmallVector<StringRef, 2> Best;
unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
for (llvm::StringMap<ModuleMap::Module *>::iterator
- I = Sub->SubModules.begin(),
- IEnd = Sub->SubModules.end();
+ I = Module->SubModules.begin(),
+ IEnd = Module->SubModules.end();
I != IEnd; ++I) {
unsigned ED = Name.edit_distance(I->getValue()->Name,
/*AllowReplacements=*/true,
@@ -1221,34 +1232,31 @@ ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
if (Best.size() == 1) {
getDiagnostics().Report(Path[I].second,
diag::err_no_submodule_suggest)
- << Path[I].first << Sub->getFullModuleName() << Best[0]
+ << Path[I].first << Module->getFullModuleName() << Best[0]
<< SourceRange(Path[0].second, Path[I-1].second)
<< FixItHint::CreateReplacement(SourceRange(Path[I].second),
Best[0]);
- Pos = Sub->SubModules.find(Best[0]);
+ Pos = Module->SubModules.find(Best[0]);
}
}
- if (Pos == Sub->SubModules.end()) {
+ if (Pos == Module->SubModules.end()) {
// No submodule by this name. Complain, and don't look for further
// submodules.
getDiagnostics().Report(Path[I].second, diag::err_no_submodule)
- << Path[I].first << Sub->getFullModuleName()
+ << Path[I].first << Module->getFullModuleName()
<< SourceRange(Path[0].second, Path[I-1].second);
break;
}
- Sub = Pos->getValue();
+ Module = Pos->getValue();
}
}
// FIXME: Tell the AST reader to make the named submodule visible.
- // FIXME: The module file's FileEntry makes a poor key indeed! Once we
- // eliminate the need for FileEntry here, the module itself will become the
- // key (which does make sense).
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = Known;
- return Known.getOpaqueValue();
+ LastModuleImportResult = Module;
+ return Module;
}
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index bcf159646a7..11a20e00621 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -177,6 +177,23 @@ ModuleMap::Module *ModuleMap::findModule(StringRef Name) {
return 0;
}
+std::pair<ModuleMap::Module *, bool>
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+ bool IsExplicit) {
+ // Try to find an existing module with this name.
+ if (Module *Found = Parent? Parent->SubModules[Name] : Modules[Name])
+ return std::make_pair(Found, false);
+
+ // Create a new module with this name.
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit);
+ if (Parent)
+ Parent->SubModules[Name] = Result;
+ else
+ Modules[Name] = Result;
+ return std::make_pair(Result, true);
+}
+
ModuleMap::Module *
ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir) {
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 2569e225b55..af12bf39fab 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/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/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index e225103f72a..cf4ea41dd59 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/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);
OpenPOWER on IntegriCloud