зеркало из https://github.com/microsoft/clang-1.git
Introduce the notion of excluded headers into the module map
description. Previously, one could emulate this behavior by placing the header in an always-unavailable submodule, but Argyrios guilted me into expressing this idea properly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165921 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
50e6b18f99
Коммит
2b49d1f0ad
|
@ -73,6 +73,9 @@ public:
|
|||
/// \brief The headers that are part of this module.
|
||||
llvm::SmallVector<const FileEntry *, 2> Headers;
|
||||
|
||||
/// \brief The headers that are explicitly excluded from this module.
|
||||
llvm::SmallVector<const FileEntry *, 2> ExcludedHeaders;
|
||||
|
||||
/// \brief The top-level headers associated with this module.
|
||||
llvm::SmallSetVector<const FileEntry *, 2> TopHeaders;
|
||||
|
||||
|
|
|
@ -52,10 +52,37 @@ class ModuleMap {
|
|||
|
||||
/// \brief The top-level modules that are known.
|
||||
llvm::StringMap<Module *> Modules;
|
||||
|
||||
|
||||
/// \brief A header that is known to reside within a given module,
|
||||
/// whether it was included or excluded.
|
||||
class KnownHeader {
|
||||
llvm::PointerIntPair<Module *, 1, bool> Storage;
|
||||
|
||||
public:
|
||||
KnownHeader() : Storage(0, false) { }
|
||||
KnownHeader(Module *M, bool Excluded) : Storage(M, Excluded) { }
|
||||
|
||||
/// \brief Retrieve the module the header is stored in.
|
||||
Module *getModule() const { return Storage.getPointer(); }
|
||||
|
||||
/// \brief Whether this header is explicitly excluded from the module.
|
||||
bool isExcluded() const { return Storage.getInt(); }
|
||||
|
||||
/// \brief Whether this header is available in the module.
|
||||
bool isAvailable() const {
|
||||
return !isExcluded() && getModule()->isAvailable();
|
||||
}
|
||||
|
||||
// \brief Whether this known header is valid (i.e., it has an
|
||||
// associated module).
|
||||
operator bool() const { return Storage.getPointer() != 0; }
|
||||
};
|
||||
|
||||
typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap;
|
||||
|
||||
/// \brief Mapping from each header to the module that owns the contents of the
|
||||
/// that header.
|
||||
llvm::DenseMap<const FileEntry *, Module *> Headers;
|
||||
HeadersMap Headers;
|
||||
|
||||
/// \brief Mapping from directories with umbrella headers to the module
|
||||
/// that is generated from the umbrella header.
|
||||
|
@ -215,7 +242,9 @@ public:
|
|||
void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir);
|
||||
|
||||
/// \brief Adds this header to the given module.
|
||||
void addHeader(Module *Mod, const FileEntry *Header);
|
||||
/// \param Excluded Whether this header is explicitly excluded from the
|
||||
/// module; otherwise, it's included in the module.
|
||||
void addHeader(Module *Mod, const FileEntry *Header, bool Excluded);
|
||||
|
||||
/// \brief Parse the given module map file, and record any modules we
|
||||
/// encounter.
|
||||
|
|
|
@ -565,7 +565,10 @@ namespace clang {
|
|||
/// submodule.
|
||||
SUBMODULE_EXPORTS = 7,
|
||||
/// \brief Specifies a required feature.
|
||||
SUBMODULE_REQUIRES = 8
|
||||
SUBMODULE_REQUIRES = 8,
|
||||
/// \brief Specifies a header that has been explicitly excluded
|
||||
/// from this submodule.
|
||||
SUBMODULE_EXCLUDED_HEADER = 9
|
||||
};
|
||||
|
||||
/// \brief Record types used within a comments block.
|
||||
|
|
|
@ -219,6 +219,13 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
|
|||
OS.write_escaped(Headers[I]->getName());
|
||||
OS << "\"\n";
|
||||
}
|
||||
|
||||
for (unsigned I = 0, N = ExcludedHeaders.size(); I != N; ++I) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "exclude header \"";
|
||||
OS.write_escaped(ExcludedHeaders[I]->getName());
|
||||
OS << "\"\n";
|
||||
}
|
||||
|
||||
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
|
||||
MI != MIEnd; ++MI)
|
||||
|
|
|
@ -146,15 +146,13 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
|
|||
}
|
||||
|
||||
Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
|
||||
llvm::DenseMap<const FileEntry *, Module *>::iterator Known
|
||||
= Headers.find(File);
|
||||
HeadersMap::iterator Known = Headers.find(File);
|
||||
if (Known != Headers.end()) {
|
||||
// If a header corresponds to an unavailable module, don't report
|
||||
// that it maps to anything.
|
||||
if (!Known->second->isAvailable())
|
||||
// If a header is not available, don't report that it maps to anything.
|
||||
if (!Known->second.isAvailable())
|
||||
return 0;
|
||||
|
||||
return Known->second;
|
||||
return Known->second.getModule();
|
||||
}
|
||||
|
||||
const DirectoryEntry *Dir = File->getDir();
|
||||
|
@ -218,7 +216,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
|
|||
UmbrellaDirs[SkippedDirs[I]] = Result;
|
||||
}
|
||||
|
||||
Headers[File] = Result;
|
||||
Headers[File] = KnownHeader(Result, /*Excluded=*/false);
|
||||
|
||||
// If a header corresponds to an unavailable module, don't report
|
||||
// that it maps to anything.
|
||||
|
@ -243,10 +241,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
|
|||
}
|
||||
|
||||
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
|
||||
llvm::DenseMap<const FileEntry *, Module *>::iterator Known
|
||||
= Headers.find(Header);
|
||||
HeadersMap::iterator Known = Headers.find(Header);
|
||||
if (Known != Headers.end())
|
||||
return !Known->second->isAvailable();
|
||||
return !Known->second.isAvailable();
|
||||
|
||||
const DirectoryEntry *Dir = Header->getDir();
|
||||
llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
|
||||
|
@ -381,7 +378,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
|
|||
|
||||
// umbrella header "umbrella-header-name"
|
||||
Result->Umbrella = UmbrellaHeader;
|
||||
Headers[UmbrellaHeader] = Result;
|
||||
Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false);
|
||||
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
|
||||
|
||||
// export *
|
||||
|
@ -447,7 +444,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
|
|||
}
|
||||
|
||||
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
|
||||
Headers[UmbrellaHeader] = Mod;
|
||||
Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false);
|
||||
Mod->Umbrella = UmbrellaHeader;
|
||||
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
|
||||
}
|
||||
|
@ -457,9 +454,13 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
|
|||
UmbrellaDirs[UmbrellaDir] = Mod;
|
||||
}
|
||||
|
||||
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) {
|
||||
Mod->Headers.push_back(Header);
|
||||
Headers[Header] = Mod;
|
||||
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
|
||||
bool Excluded) {
|
||||
if (Excluded)
|
||||
Mod->ExcludedHeaders.push_back(Header);
|
||||
else
|
||||
Mod->Headers.push_back(Header);
|
||||
Headers[Header] = KnownHeader(Mod, Excluded);
|
||||
}
|
||||
|
||||
const FileEntry *
|
||||
|
@ -479,12 +480,10 @@ void ModuleMap::dump() {
|
|||
M->getValue()->print(llvm::errs(), 2);
|
||||
|
||||
llvm::errs() << "Headers:";
|
||||
for (llvm::DenseMap<const FileEntry *, Module *>::iterator
|
||||
H = Headers.begin(),
|
||||
HEnd = Headers.end();
|
||||
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
|
||||
H != HEnd; ++H) {
|
||||
llvm::errs() << " \"" << H->first->getName() << "\" -> "
|
||||
<< H->second->getFullModuleName() << "\n";
|
||||
<< H->second.getModule()->getFullModuleName() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -545,6 +544,7 @@ namespace clang {
|
|||
EndOfFile,
|
||||
HeaderKeyword,
|
||||
Identifier,
|
||||
ExcludeKeyword,
|
||||
ExplicitKeyword,
|
||||
ExportKeyword,
|
||||
FrameworkKeyword,
|
||||
|
@ -623,7 +623,7 @@ namespace clang {
|
|||
bool parseModuleId(ModuleId &Id);
|
||||
void parseModuleDecl();
|
||||
void parseRequiresDecl();
|
||||
void parseHeaderDecl(SourceLocation UmbrellaLoc);
|
||||
void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
|
||||
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
|
||||
void parseExportDecl();
|
||||
void parseInferredSubmoduleDecl(bool Explicit);
|
||||
|
@ -666,6 +666,7 @@ retry:
|
|||
Tok.StringLength = LToken.getLength();
|
||||
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
|
||||
.Case("header", MMToken::HeaderKeyword)
|
||||
.Case("exclude", MMToken::ExcludeKeyword)
|
||||
.Case("explicit", MMToken::ExplicitKeyword)
|
||||
.Case("export", MMToken::ExportKeyword)
|
||||
.Case("framework", MMToken::FrameworkKeyword)
|
||||
|
@ -1044,14 +1045,25 @@ void ModuleMapParser::parseModuleDecl() {
|
|||
case MMToken::UmbrellaKeyword: {
|
||||
SourceLocation UmbrellaLoc = consumeToken();
|
||||
if (Tok.is(MMToken::HeaderKeyword))
|
||||
parseHeaderDecl(UmbrellaLoc);
|
||||
parseHeaderDecl(UmbrellaLoc, SourceLocation());
|
||||
else
|
||||
parseUmbrellaDirDecl(UmbrellaLoc);
|
||||
break;
|
||||
}
|
||||
|
||||
case MMToken::ExcludeKeyword: {
|
||||
SourceLocation ExcludeLoc = consumeToken();
|
||||
if (Tok.is(MMToken::HeaderKeyword)) {
|
||||
parseHeaderDecl(SourceLocation(), ExcludeLoc);
|
||||
} else {
|
||||
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
||||
<< "exclude";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MMToken::HeaderKeyword:
|
||||
parseHeaderDecl(SourceLocation());
|
||||
parseHeaderDecl(SourceLocation(), SourceLocation());
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1153,12 +1165,15 @@ static bool isBuiltinHeader(StringRef FileName) {
|
|||
///
|
||||
/// header-declaration:
|
||||
/// 'umbrella'[opt] 'header' string-literal
|
||||
void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
|
||||
/// 'exclude'[opt] 'header' string-literal
|
||||
void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
|
||||
SourceLocation ExcludeLoc) {
|
||||
assert(Tok.is(MMToken::HeaderKeyword));
|
||||
consumeToken();
|
||||
|
||||
bool Umbrella = UmbrellaLoc.isValid();
|
||||
|
||||
bool Exclude = ExcludeLoc.isValid();
|
||||
assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'");
|
||||
// Parse the header name.
|
||||
if (!Tok.is(MMToken::StringLiteral)) {
|
||||
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
||||
|
@ -1236,15 +1251,15 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
|
|||
// FIXME: We shouldn't be eagerly stat'ing every file named in a module map.
|
||||
// Come up with a lazy way to do this.
|
||||
if (File) {
|
||||
if (const Module *OwningModule = Map.Headers[File]) {
|
||||
if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
|
||||
Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
|
||||
<< FileName << OwningModule->getFullModuleName();
|
||||
<< FileName << OwningModule.getModule()->getFullModuleName();
|
||||
HadError = true;
|
||||
} else if (Umbrella) {
|
||||
const DirectoryEntry *UmbrellaDir = File->getDir();
|
||||
if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
|
||||
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
|
||||
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
|
||||
<< OwningModule->getFullModuleName();
|
||||
<< UmbrellaModule->getFullModuleName();
|
||||
HadError = true;
|
||||
} else {
|
||||
// Record this umbrella header.
|
||||
|
@ -1252,11 +1267,11 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
|
|||
}
|
||||
} else {
|
||||
// Record this header.
|
||||
Map.addHeader(ActiveModule, File);
|
||||
Map.addHeader(ActiveModule, File, Exclude);
|
||||
|
||||
// If there is a builtin counterpart to this file, add it now.
|
||||
if (BuiltinFile)
|
||||
Map.addHeader(ActiveModule, BuiltinFile);
|
||||
Map.addHeader(ActiveModule, BuiltinFile, Exclude);
|
||||
}
|
||||
} else {
|
||||
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
|
||||
|
@ -1489,6 +1504,7 @@ bool ModuleMapParser::parseModuleMapFile() {
|
|||
break;
|
||||
|
||||
case MMToken::Comma:
|
||||
case MMToken::ExcludeKeyword:
|
||||
case MMToken::ExportKeyword:
|
||||
case MMToken::HeaderKeyword:
|
||||
case MMToken::Identifier:
|
||||
|
|
|
@ -3322,7 +3322,27 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
|
|||
if (std::find(CurrentModule->Headers.begin(),
|
||||
CurrentModule->Headers.end(),
|
||||
File) == CurrentModule->Headers.end())
|
||||
ModMap.addHeader(CurrentModule, File);
|
||||
ModMap.addHeader(CurrentModule, File, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SUBMODULE_EXCLUDED_HEADER: {
|
||||
if (First) {
|
||||
Error("missing submodule metadata record at beginning of block");
|
||||
return Failure;
|
||||
}
|
||||
|
||||
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())
|
||||
ModMap.addHeader(CurrentModule, File, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1983,6 +1983,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
|
|||
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature
|
||||
unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev);
|
||||
|
||||
Abbrev = new BitCodeAbbrev();
|
||||
Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER));
|
||||
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
|
||||
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
|
||||
|
||||
// Write the submodule metadata block.
|
||||
RecordData Record;
|
||||
Record.push_back(getNumberOfModules(WritingModule));
|
||||
|
@ -2044,6 +2049,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
|
|||
Stream.EmitRecordWithBlob(HeaderAbbrev, Record,
|
||||
Mod->Headers[I]->getName());
|
||||
}
|
||||
// Emit the excluded headers.
|
||||
for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) {
|
||||
Record.clear();
|
||||
Record.push_back(SUBMODULE_EXCLUDED_HEADER);
|
||||
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
|
||||
Mod->ExcludedHeaders[I]->getName());
|
||||
}
|
||||
for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
|
||||
Record.clear();
|
||||
Record.push_back(SUBMODULE_TOPHEADER);
|
||||
|
|
|
@ -2,8 +2,5 @@ framework module NoUmbrella [system] {
|
|||
umbrella "Headers"
|
||||
module * { }
|
||||
|
||||
module unavailable {
|
||||
requires unavailable
|
||||
header "Boom.h"
|
||||
}
|
||||
exclude header "Boom.h"
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче