summaryrefslogtreecommitdiffstats
path: root/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Lex/ModuleMap.cpp')
-rw-r--r--lib/Lex/ModuleMap.cpp392
1 files changed, 291 insertions, 101 deletions
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 3e7a44c..f4dfa12 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -27,7 +27,7 @@
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/PathV2.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <stdlib.h>
#if defined(LLVM_ON_UNIX)
@@ -83,18 +83,18 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
return Context;
}
-ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC,
+ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC,
const LangOptions &LangOpts, const TargetInfo *Target,
HeaderSearch &HeaderInfo)
- : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo),
- BuiltinIncludeDir(0)
-{
+ : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target),
+ HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0),
+ SourceModule(0) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
new DiagnosticsEngine(DiagIDs, new DiagnosticOptions));
Diags->setClient(new ForwardingDiagnosticConsumer(DC),
/*ShouldOwnClient=*/true);
- SourceMgr = new SourceManager(*Diags, FileMgr);
+ Diags->setSourceManager(&SourceMgr);
}
ModuleMap::~ModuleMap() {
@@ -103,8 +103,6 @@ ModuleMap::~ModuleMap() {
I != IEnd; ++I) {
delete I->getValue();
}
-
- delete SourceMgr;
}
void ModuleMap::setTarget(const TargetInfo &Target) {
@@ -168,14 +166,41 @@ static bool isBuiltinHeader(StringRef FileName) {
.Default(false);
}
-Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
+ModuleMap::KnownHeader
+ModuleMap::findModuleForHeader(const FileEntry *File,
+ Module *RequestingModule) {
HeadersMap::iterator Known = Headers.find(File);
if (Known != Headers.end()) {
- // If a header is not available, don't report that it maps to anything.
- if (!Known->second.isAvailable())
- return 0;
+ ModuleMap::KnownHeader Result = KnownHeader();
+
+ // Iterate over all modules that 'File' is part of to find the best fit.
+ for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ // Cannot use a module if the header is excluded or unavailable in it.
+ if (I->getRole() == ModuleMap::ExcludedHeader ||
+ !I->getModule()->isAvailable())
+ continue;
- return Known->second.getModule();
+ // If 'File' is part of 'RequestingModule', 'RequestingModule' is the
+ // module we are looking for.
+ if (I->getModule() == RequestingModule)
+ return *I;
+
+ // If uses need to be specified explicitly, we are only allowed to return
+ // modules that are explicitly used by the requesting module.
+ if (RequestingModule && LangOpts.ModulesDeclUse &&
+ std::find(RequestingModule->DirectUses.begin(),
+ RequestingModule->DirectUses.end(),
+ I->getModule()) == RequestingModule->DirectUses.end())
+ continue;
+ Result = *I;
+ // If 'File' is a public header of this module, this is as good as we
+ // are going to get.
+ if (I->getRole() == ModuleMap::NormalHeader)
+ break;
+ }
+ return Result;
}
// If we've found a builtin header within Clang's builtin include directory,
@@ -183,18 +208,11 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
// specific module (e.g., in /usr/include).
if (File->getDir() == BuiltinIncludeDir &&
isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
- SmallVector<Module *, 4> AllModules;
- HeaderInfo.collectAllModules(AllModules);
+ HeaderInfo.loadTopLevelSystemModules();
// Check again.
- Known = Headers.find(File);
- if (Known != Headers.end()) {
- // If a header is not available, don't report that it maps to anything.
- if (!Known->second.isAvailable())
- return 0;
-
- return Known->second.getModule();
- }
+ if (Headers.find(File) != Headers.end())
+ return findModuleForHeader(File, RequestingModule);
}
const DirectoryEntry *Dir = File->getDir();
@@ -204,7 +222,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
// frameworks moving from top-level frameworks to embedded frameworks tend
// to be symlinked from the top-level location to the embedded location,
// and we need to resolve lookups as if we had found the embedded location.
- StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir);
+ StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
@@ -263,14 +281,14 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
UmbrellaDirs[SkippedDirs[I]] = Result;
}
- Headers[File] = KnownHeader(Result, /*Excluded=*/false);
+ Headers[File].push_back(KnownHeader(Result, NormalHeader));
// If a header corresponds to an unavailable module, don't report
// that it maps to anything.
if (!Result->isAvailable())
- return 0;
+ return KnownHeader();
- return Result;
+ return Headers[File].back();
}
SkippedDirs.push_back(Dir);
@@ -281,16 +299,24 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
} while (Dir);
- return 0;
+ return KnownHeader();
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
HeadersMap::const_iterator Known = Headers.find(Header);
- if (Known != Headers.end())
- return !Known->second.isAvailable();
+ if (Known != Headers.end()) {
+ for (SmallVectorImpl<KnownHeader>::const_iterator
+ I = Known->second.begin(),
+ E = Known->second.end();
+ I != E; ++I) {
+ if (I->isAvailable())
+ return false;
+ }
+ return true;
+ }
const DirectoryEntry *Dir = Header->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
@@ -347,7 +373,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr->getFileManager().getDirectory(DirName);
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
} while (Dir);
return false;
@@ -388,8 +414,17 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
// Create a new module with this name.
Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
IsExplicit);
- if (!Parent)
+ if (LangOpts.CurrentModule == Name) {
+ SourceModule = Result;
+ SourceModuleName = Name;
+ }
+ if (!Parent) {
Modules[Name] = Result;
+ if (!LangOpts.CurrentModule.empty() && !CompilingModule &&
+ Name == LangOpts.CurrentModule) {
+ CompilingModule = Result;
+ }
+ }
return std::make_pair(Result, true);
}
@@ -443,7 +478,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
return Mod;
- FileManager &FileMgr = SourceMgr->getFileManager();
+ FileManager &FileMgr = SourceMgr.getFileManager();
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
@@ -455,7 +490,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// top-level framework, and we need to infer as if we were naming the
// top-level framework.
StringRef FrameworkDirName
- = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
+ = SourceMgr.getFileManager().getCanonicalName(FrameworkDir);
bool canInfer = false;
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
@@ -472,7 +507,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
SmallString<128> ModMapPath = Parent;
llvm::sys::path::append(ModMapPath, "module.map");
if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
- parseModuleMapFile(ModMapFile);
+ parseModuleMapFile(ModMapFile, IsSystem);
inferred = InferredDirectories.find(ParentDir);
}
@@ -503,8 +538,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
- llvm::sys::path::append(UmbrellaName, "Headers");
- llvm::sys::path::append(UmbrellaName, ModuleName + ".h");
+ llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
const FileEntry *UmbrellaHeader = FileMgr.getFile(UmbrellaName);
// FIXME: If there's no umbrella header, we could probably scan the
@@ -515,6 +549,10 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false);
+ if (LangOpts.CurrentModule == ModuleName) {
+ SourceModule = Result;
+ SourceModuleName = ModuleName;
+ }
if (IsSystem)
Result->IsSystem = IsSystem;
@@ -523,7 +561,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// umbrella header "umbrella-header-name"
Result->Umbrella = UmbrellaHeader;
- Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Result, NormalHeader));
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
@@ -538,11 +576,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
SmallString<128> SubframeworksDirName
= StringRef(FrameworkDir->getName());
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
- SmallString<128> SubframeworksDirNameNative;
- llvm::sys::path::native(SubframeworksDirName.str(),
- SubframeworksDirNameNative);
+ llvm::sys::path::native(SubframeworksDirName);
for (llvm::sys::fs::directory_iterator
- Dir(SubframeworksDirNameNative.str(), EC), DirEnd;
+ Dir(SubframeworksDirName.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
@@ -589,7 +625,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
- Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false);
+ Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
Mod->Umbrella = UmbrellaHeader;
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
@@ -600,23 +636,27 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
}
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
- bool Excluded) {
- if (Excluded) {
+ ModuleHeaderRole Role) {
+ if (Role == ExcludedHeader) {
Mod->ExcludedHeaders.push_back(Header);
} else {
- Mod->Headers.push_back(Header);
- HeaderInfo.MarkFileModuleHeader(Header);
+ if (Role == PrivateHeader)
+ Mod->PrivateHeaders.push_back(Header);
+ else
+ Mod->NormalHeaders.push_back(Header);
+ bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule;
+ HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader);
}
- Headers[Header] = KnownHeader(Mod, Excluded);
+ Headers[Header].push_back(KnownHeader(Mod, Role));
}
const FileEntry *
ModuleMap::getContainingModuleMapFile(Module *Module) const {
- if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
+ if (Module->DefinitionLoc.isInvalid())
return 0;
- return SourceMgr->getFileEntryForID(
- SourceMgr->getFileID(Module->DefinitionLoc));
+ return SourceMgr.getFileEntryForID(
+ SourceMgr.getFileID(Module->DefinitionLoc));
}
void ModuleMap::dump() {
@@ -629,8 +669,15 @@ void ModuleMap::dump() {
llvm::errs() << "Headers:";
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
H != HEnd; ++H) {
- llvm::errs() << " \"" << H->first->getName() << "\" -> "
- << H->second.getModule()->getFullModuleName() << "\n";
+ llvm::errs() << " \"" << H->first->getName() << "\" -> ";
+ for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),
+ E = H->second.end();
+ I != E; ++I) {
+ if (I != H->second.begin())
+ llvm::errs() << ",";
+ llvm::errs() << I->getModule()->getFullModuleName();
+ }
+ llvm::errs() << "\n";
}
}
@@ -648,6 +695,20 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
return HadError;
}
+bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedDirectUses.size(); I != N; ++I) {
+ Module *DirectUse =
+ resolveModuleId(Mod->UnresolvedDirectUses[I], Mod, Complain);
+ if (DirectUse)
+ Mod->DirectUses.push_back(DirectUse);
+ else
+ HadError = true;
+ }
+ Mod->UnresolvedDirectUses.clear();
+ return HadError;
+}
+
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
bool HadError = false;
for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
@@ -683,7 +744,7 @@ Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
while (const FileEntry *ExpansionFile
= SrcMgr.getFileEntryForID(ExpansionFileID)) {
// Find the module that owns this header (if any).
- if (Module *Mod = findModuleForHeader(ExpansionFile))
+ if (Module *Mod = findModuleForHeader(ExpansionFile).getModule())
return Mod;
// No module owns this header, so look up the inclusion chain to see if
@@ -712,14 +773,18 @@ namespace clang {
EndOfFile,
HeaderKeyword,
Identifier,
+ Exclaim,
ExcludeKeyword,
ExplicitKeyword,
ExportKeyword,
+ ExternKeyword,
FrameworkKeyword,
LinkKeyword,
ModuleKeyword,
Period,
+ PrivateKeyword,
UmbrellaKeyword,
+ UseKeyword,
RequiresKeyword,
Star,
StringLiteral,
@@ -780,6 +845,9 @@ namespace clang {
/// \brief The directory containing Clang-supplied headers.
const DirectoryEntry *BuiltinIncludeDir;
+ /// \brief Whether this module map is in a system header directory.
+ bool IsSystem;
+
/// \brief Whether an error occurred.
bool HadError;
@@ -803,10 +871,13 @@ namespace clang {
typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
+ void parseExternModuleDecl();
void parseRequiresDecl();
- void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
+ void parseHeaderDecl(clang::MMToken::TokenKind,
+ SourceLocation LeadingLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
+ void parseUseDecl();
void parseLinkDecl();
void parseConfigMacros();
void parseConflict();
@@ -821,10 +892,11 @@ namespace clang {
DiagnosticsEngine &Diags,
ModuleMap &Map,
const DirectoryEntry *Directory,
- const DirectoryEntry *BuiltinIncludeDir)
+ const DirectoryEntry *BuiltinIncludeDir,
+ bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
- HadError(false), ActiveModule(0)
+ Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
+ IsSystem(IsSystem), HadError(false), ActiveModule(0)
{
Tok.clear();
consumeToken();
@@ -852,12 +924,15 @@ retry:
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
+ .Case("extern", MMToken::ExternKeyword)
.Case("framework", MMToken::FrameworkKeyword)
.Case("header", MMToken::HeaderKeyword)
.Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword)
+ .Case("private", MMToken::PrivateKeyword)
.Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
+ .Case("use", MMToken::UseKeyword)
.Default(MMToken::Identifier);
break;
@@ -893,6 +968,10 @@ retry:
Tok.Kind = MMToken::Star;
break;
+ case tok::exclaim:
+ Tok.Kind = MMToken::Exclaim;
+ break;
+
case tok::string_literal: {
if (LToken.hasUDSuffix()) {
Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
@@ -1019,6 +1098,7 @@ namespace {
/// \brief Parse a module declaration.
///
/// module-declaration:
+/// 'extern' 'module' module-id string-literal
/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
/// { module-member* }
///
@@ -1034,7 +1114,12 @@ namespace {
/// inferred-submodule-declaration
void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
- Tok.is(MMToken::FrameworkKeyword));
+ Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword));
+ if (Tok.is(MMToken::ExternKeyword)) {
+ parseExternModuleDecl();
+ return;
+ }
+
// Parse 'explicit' or 'framework' keyword, if present.
SourceLocation ExplicitLoc;
bool Explicit = false;
@@ -1159,7 +1244,7 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
- if (Attrs.IsSystem)
+ if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
bool Done = false;
@@ -1179,14 +1264,19 @@ void ModuleMapParser::parseModuleDecl() {
break;
case MMToken::ExplicitKeyword:
+ case MMToken::ExternKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
parseModuleDecl();
break;
-
+
case MMToken::ExportKeyword:
parseExportDecl();
break;
+
+ case MMToken::UseKeyword:
+ parseUseDecl();
+ break;
case MMToken::RequiresKeyword:
parseRequiresDecl();
@@ -1195,7 +1285,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::UmbrellaKeyword: {
SourceLocation UmbrellaLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword))
- parseHeaderDecl(UmbrellaLoc, SourceLocation());
+ parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
else
parseUmbrellaDirDecl(UmbrellaLoc);
break;
@@ -1204,7 +1294,7 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::ExcludeKeyword: {
SourceLocation ExcludeLoc = consumeToken();
if (Tok.is(MMToken::HeaderKeyword)) {
- parseHeaderDecl(SourceLocation(), ExcludeLoc);
+ parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
} else {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
<< "exclude";
@@ -1212,8 +1302,19 @@ void ModuleMapParser::parseModuleDecl() {
break;
}
+ case MMToken::PrivateKeyword: {
+ SourceLocation PrivateLoc = consumeToken();
+ if (Tok.is(MMToken::HeaderKeyword)) {
+ parseHeaderDecl(MMToken::PrivateKeyword, PrivateLoc);
+ } else {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
+ << "private";
+ }
+ break;
+ }
+
case MMToken::HeaderKeyword:
- parseHeaderDecl(SourceLocation(), SourceLocation());
+ parseHeaderDecl(MMToken::HeaderKeyword, SourceLocation());
break;
case MMToken::LinkKeyword:
@@ -1246,14 +1347,61 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = PreviousActiveModule;
}
+/// \brief Parse an extern module declaration.
+///
+/// extern module-declaration:
+/// 'extern' 'module' module-id string-literal
+void ModuleMapParser::parseExternModuleDecl() {
+ assert(Tok.is(MMToken::ExternKeyword));
+ consumeToken(); // 'extern' keyword
+
+ // Parse 'module' keyword.
+ if (!Tok.is(MMToken::ModuleKeyword)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
+ consumeToken();
+ HadError = true;
+ return;
+ }
+ consumeToken(); // 'module' keyword
+
+ // Parse the module name.
+ ModuleId Id;
+ if (parseModuleId(Id)) {
+ HadError = true;
+ return;
+ }
+
+ // Parse the referenced module map file name.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);
+ HadError = true;
+ return;
+ }
+ std::string FileName = Tok.getString();
+ consumeToken(); // filename
+
+ StringRef FileNameRef = FileName;
+ SmallString<128> ModuleMapFileName;
+ if (llvm::sys::path::is_relative(FileNameRef)) {
+ ModuleMapFileName += Directory->getName();
+ llvm::sys::path::append(ModuleMapFileName, FileName);
+ FileNameRef = ModuleMapFileName.str();
+ }
+ if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef))
+ Map.parseModuleMapFile(File, /*IsSystem=*/false);
+}
+
/// \brief Parse a requires declaration.
///
/// requires-declaration:
/// 'requires' feature-list
///
/// feature-list:
-/// identifier ',' feature-list
-/// identifier
+/// feature ',' feature-list
+/// feature
+///
+/// feature:
+/// '!'[opt] identifier
void ModuleMapParser::parseRequiresDecl() {
assert(Tok.is(MMToken::RequiresKeyword));
@@ -1262,6 +1410,12 @@ void ModuleMapParser::parseRequiresDecl() {
// Parse the feature-list.
do {
+ bool RequiredState = true;
+ if (Tok.is(MMToken::Exclaim)) {
+ RequiredState = false;
+ consumeToken();
+ }
+
if (!Tok.is(MMToken::Identifier)) {
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
HadError = true;
@@ -1273,7 +1427,8 @@ void ModuleMapParser::parseRequiresDecl() {
consumeToken();
// Add this feature.
- ActiveModule->addRequirement(Feature, Map.LangOpts, *Map.Target);
+ ActiveModule->addRequirement(Feature, RequiredState,
+ Map.LangOpts, *Map.Target);
if (!Tok.is(MMToken::Comma))
break;
@@ -1298,10 +1453,8 @@ static void appendSubframeworkPaths(Module *Mod,
return;
// Add Frameworks/Name.framework for each subframework.
- for (unsigned I = Paths.size() - 1; I != 0; --I) {
- llvm::sys::path::append(Path, "Frameworks");
- llvm::sys::path::append(Path, Paths[I-1] + ".framework");
- }
+ for (unsigned I = Paths.size() - 1; I != 0; --I)
+ llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
}
/// \brief Parse a header declaration.
@@ -1309,14 +1462,11 @@ static void appendSubframeworkPaths(Module *Mod,
/// header-declaration:
/// 'umbrella'[opt] 'header' string-literal
/// 'exclude'[opt] 'header' string-literal
-void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
- SourceLocation ExcludeLoc) {
+void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
+ SourceLocation LeadingLoc) {
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)
@@ -1328,7 +1478,7 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
SourceLocation FileNameLoc = consumeToken();
// Check whether we already have an umbrella.
- if (Umbrella && ActiveModule->Umbrella) {
+ if (LeadingToken == MMToken::UmbrellaKeyword && ActiveModule->Umbrella) {
Diags.Report(FileNameLoc, diag::err_mmap_umbrella_clash)
<< ActiveModule->getFullModuleName();
HadError = true;
@@ -1355,15 +1505,13 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
appendSubframeworkPaths(ActiveModule, PathName);
// Check whether this file is in the public headers.
- llvm::sys::path::append(PathName, "Headers");
- llvm::sys::path::append(PathName, FileName);
+ llvm::sys::path::append(PathName, "Headers", FileName);
File = SourceMgr.getFileManager().getFile(PathName);
if (!File) {
// Check whether this file is in the private headers.
PathName.resize(PathLength);
- llvm::sys::path::append(PathName, "PrivateHeaders");
- llvm::sys::path::append(PathName, FileName);
+ llvm::sys::path::append(PathName, "PrivateHeaders", FileName);
File = SourceMgr.getFileManager().getFile(PathName);
}
} else {
@@ -1374,8 +1522,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
// If this is a system module with a top-level header, this header
// may have a counterpart (or replacement) in the set of headers
// supplied by Clang. Find that builtin header.
- if (ActiveModule->IsSystem && !Umbrella && BuiltinIncludeDir &&
- BuiltinIncludeDir != Directory && isBuiltinHeader(FileName)) {
+ if (ActiveModule->IsSystem && LeadingToken != MMToken::UmbrellaKeyword &&
+ BuiltinIncludeDir && BuiltinIncludeDir != Directory &&
+ isBuiltinHeader(FileName)) {
SmallString<128> BuiltinPathName(BuiltinIncludeDir->getName());
llvm::sys::path::append(BuiltinPathName, FileName);
BuiltinFile = SourceMgr.getFileManager().getFile(BuiltinPathName);
@@ -1394,14 +1543,10 @@ 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 (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) {
- Diags.Report(FileNameLoc, diag::err_mmap_header_conflict)
- << FileName << OwningModule.getModule()->getFullModuleName();
- HadError = true;
- } else if (Umbrella) {
+ if (LeadingToken == MMToken::UmbrellaKeyword) {
const DirectoryEntry *UmbrellaDir = File->getDir();
if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) {
- Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
+ Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash)
<< UmbrellaModule->getFullModuleName();
HadError = true;
} else {
@@ -1410,17 +1555,25 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
}
} else {
// Record this header.
- Map.addHeader(ActiveModule, File, Exclude);
+ ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
+ if (LeadingToken == MMToken::ExcludeKeyword)
+ Role = ModuleMap::ExcludedHeader;
+ else if (LeadingToken == MMToken::PrivateKeyword)
+ Role = ModuleMap::PrivateHeader;
+ else
+ assert(LeadingToken == MMToken::HeaderKeyword);
+
+ Map.addHeader(ActiveModule, File, Role);
// If there is a builtin counterpart to this file, add it now.
if (BuiltinFile)
- Map.addHeader(ActiveModule, BuiltinFile, Exclude);
+ Map.addHeader(ActiveModule, BuiltinFile, Role);
}
- } else if (!Exclude) {
+ } else if (LeadingToken != MMToken::ExcludeKeyword) {
// Ignore excluded header files. They're optional anyway.
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
- << Umbrella << FileName;
+ << (LeadingToken == MMToken::UmbrellaKeyword) << FileName;
HadError = true;
}
}
@@ -1514,7 +1667,7 @@ void ModuleMapParser::parseExportDecl() {
break;
}
- Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
HadError = true;
return;
} while (true);
@@ -1525,6 +1678,38 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
+/// \brief Parse a module uses declaration.
+///
+/// uses-declaration:
+/// 'uses' wildcard-module-id
+void ModuleMapParser::parseUseDecl() {
+ assert(Tok.is(MMToken::UseKeyword));
+ consumeToken();
+ // Parse the module-id.
+ ModuleId ParsedModuleId;
+
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ ParsedModuleId.push_back(
+ std::make_pair(Tok.getString(), Tok.getLocation()));
+ consumeToken();
+
+ if (Tok.is(MMToken::Period)) {
+ consumeToken();
+ continue;
+ }
+
+ break;
+ }
+
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
+ HadError = true;
+ return;
+ } while (true);
+
+ ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
+}
+
/// \brief Parse a link declaration.
///
/// module-declaration:
@@ -1787,6 +1972,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
case MMToken::ExplicitKeyword:
case MMToken::ModuleKeyword:
case MMToken::HeaderKeyword:
+ case MMToken::PrivateKeyword:
case MMToken::UmbrellaKeyword:
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
@@ -1897,6 +2083,7 @@ bool ModuleMapParser::parseModuleMapFile() {
return HadError;
case MMToken::ExplicitKeyword:
+ case MMToken::ExternKeyword:
case MMToken::ModuleKeyword:
case MMToken::FrameworkKeyword:
parseModuleDecl();
@@ -1905,6 +2092,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::Comma:
case MMToken::ConfigMacros:
case MMToken::Conflict:
+ case MMToken::Exclaim:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
@@ -1913,12 +2101,14 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::LinkKeyword:
case MMToken::LSquare:
case MMToken::Period:
+ case MMToken::PrivateKeyword:
case MMToken::RBrace:
case MMToken::RSquare:
case MMToken::RequiresKeyword:
case MMToken::Star:
case MMToken::StringLiteral:
case MMToken::UmbrellaKeyword:
+ case MMToken::UseKeyword:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
HadError = true;
consumeToken();
@@ -1927,23 +2117,23 @@ bool ModuleMapParser::parseModuleMapFile() {
} while (true);
}
-bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
llvm::DenseMap<const FileEntry *, bool>::iterator Known
= ParsedModuleMap.find(File);
if (Known != ParsedModuleMap.end())
return Known->second;
assert(Target != 0 && "Missing target information");
- FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
- const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
+ FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
+ const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
// Parse this module map file.
- Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
+ Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
Diags->getClient()->BeginSourceFile(MMapLangOpts);
- ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(),
- BuiltinIncludeDir);
+ ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(),
+ BuiltinIncludeDir, IsSystem);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
ParsedModuleMap[File] = Result;
OpenPOWER on IntegriCloud