aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Lex/ModuleMap.cpp
diff options
context:
space:
mode:
authorMichael Spencer <bigcheesegs@gmail.com>2025-02-26 14:32:50 -0800
committerGitHub <noreply@github.com>2025-02-26 14:32:50 -0800
commit8fb88f568011fb916cda9d7927ac97c6751a8b89 (patch)
tree4fc0dcd235ecfc4b15dcae6d4f8ea752c7bdba74 /clang/lib/Lex/ModuleMap.cpp
parent39bab1de33333ee3c62b586c4e8d26f8c443bc60 (diff)
downloadllvm-8fb88f568011fb916cda9d7927ac97c6751a8b89.zip
llvm-8fb88f568011fb916cda9d7927ac97c6751a8b89.tar.gz
llvm-8fb88f568011fb916cda9d7927ac97c6751a8b89.tar.bz2
[clang][modules] Separate parsing of modulemaps (#119740)
This separates out parsing of modulemaps from updating the `clang::ModuleMap` information. Currently this has no effect other than slightly changing diagnostics. Upcoming changes will use this to allow searching for modules without fully processing modulemaps. This creates a new `modulemap` namespace because there are too many things called ModuleMap* right now that mean different things. I'd like to clean this up, but I'm not sure yet what I want to call everything. This also drops the `SourceLocation` from `moduleMapFileRead`. This is never used in tree, and in future patches I plan to make the modulemap parser use a different `SourceManager` so that we can share modulemap parsing between `CompilerInstance`s. This will make the `SourceLocation` meaningless.
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r--clang/lib/Lex/ModuleMap.cpp1498
1 files changed, 237 insertions, 1261 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 998e2b9..e6985a4 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -24,9 +24,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Token.h"
+#include "clang/Lex/ModuleMapFile.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -34,7 +32,6 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
@@ -1461,419 +1458,80 @@ bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
//----------------------------------------------------------------------------//
namespace clang {
+class ModuleMapParser {
+ modulemap::ModuleMapFile &MMF;
+ SourceManager &SourceMgr;
- /// A token in a module map file.
- struct MMToken {
- enum TokenKind {
- Comma,
- ConfigMacros,
- Conflict,
- EndOfFile,
- HeaderKeyword,
- Identifier,
- Exclaim,
- ExcludeKeyword,
- ExplicitKeyword,
- ExportKeyword,
- ExportAsKeyword,
- ExternKeyword,
- FrameworkKeyword,
- LinkKeyword,
- ModuleKeyword,
- Period,
- PrivateKeyword,
- UmbrellaKeyword,
- UseKeyword,
- RequiresKeyword,
- Star,
- StringLiteral,
- IntegerLiteral,
- TextualKeyword,
- LBrace,
- RBrace,
- LSquare,
- RSquare
- } Kind;
-
- SourceLocation::UIntTy Location;
- unsigned StringLength;
- union {
- // If Kind != IntegerLiteral.
- const char *StringData;
-
- // If Kind == IntegerLiteral.
- uint64_t IntegerValue;
- };
-
- void clear() {
- Kind = EndOfFile;
- Location = 0;
- StringLength = 0;
- StringData = nullptr;
- }
+ DiagnosticsEngine &Diags;
+ ModuleMap &Map;
- bool is(TokenKind K) const { return Kind == K; }
+ /// The current module map file.
+ FileID ModuleMapFID;
- SourceLocation getLocation() const {
- return SourceLocation::getFromRawEncoding(Location);
- }
+ /// Source location of most recent parsed module declaration
+ SourceLocation CurrModuleDeclLoc;
- uint64_t getInteger() const {
- return Kind == IntegerLiteral ? IntegerValue : 0;
- }
+ /// The directory that file names in this module map file should
+ /// be resolved relative to.
+ DirectoryEntryRef Directory;
- StringRef getString() const {
- return Kind == IntegerLiteral ? StringRef()
- : StringRef(StringData, StringLength);
- }
- };
+ /// Whether this module map is in a system header directory.
+ bool IsSystem;
- class ModuleMapParser {
- Lexer &L;
- SourceManager &SourceMgr;
-
- /// Default target information, used only for string literal
- /// parsing.
- const TargetInfo *Target;
-
- DiagnosticsEngine &Diags;
- ModuleMap &Map;
-
- /// The current module map file.
- FileID ModuleMapFID;
-
- /// Source location of most recent parsed module declaration
- SourceLocation CurrModuleDeclLoc;
-
- /// The directory that file names in this module map file should
- /// be resolved relative to.
- DirectoryEntryRef Directory;
-
- /// Whether this module map is in a system header directory.
- bool IsSystem;
-
- /// Whether an error occurred.
- bool HadError = false;
-
- /// Stores string data for the various string literals referenced
- /// during parsing.
- llvm::BumpPtrAllocator StringData;
-
- /// The current token.
- MMToken Tok;
-
- /// The active module.
- Module *ActiveModule = nullptr;
-
- /// Whether a module uses the 'requires excluded' hack to mark its
- /// contents as 'textual'.
- ///
- /// On older Darwin SDK versions, 'requires excluded' is used to mark the
- /// contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as
- /// non-modular headers. For backwards compatibility, we continue to
- /// support this idiom for just these modules, and map the headers to
- /// 'textual' to match the original intent.
- llvm::SmallPtrSet<Module *, 2> UsesRequiresExcludedHack;
-
- /// Consume the current token and return its location.
- SourceLocation consumeToken();
-
- /// Skip tokens until we reach the a token with the given kind
- /// (or the end of the file).
- void skipUntil(MMToken::TokenKind K);
-
- bool parseModuleId(ModuleId &Id);
- void parseModuleDecl();
- void parseExternModuleDecl();
- void parseRequiresDecl();
- void parseHeaderDecl(MMToken::TokenKind, SourceLocation LeadingLoc);
- void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
- void parseExportDecl();
- void parseExportAsDecl();
- void parseUseDecl();
- void parseLinkDecl();
- void parseConfigMacros();
- void parseConflict();
- void parseInferredModuleDecl(bool Framework, bool Explicit);
-
- /// Private modules are canonicalized as Foo_Private. Clang provides extra
- /// module map search logic to find the appropriate private module when PCH
- /// is used with implicit module maps. Warn when private modules are written
- /// in other ways (FooPrivate and Foo.Private), providing notes and fixits.
- void diagnosePrivateModules(SourceLocation ExplicitLoc,
- SourceLocation FrameworkLoc);
-
- using Attributes = ModuleMap::Attributes;
-
- bool parseOptionalAttributes(Attributes &Attrs);
-
- public:
- ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
- const TargetInfo *Target, DiagnosticsEngine &Diags,
- ModuleMap &Map, FileID ModuleMapFID,
- DirectoryEntryRef Directory, bool IsSystem)
- : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {
- Tok.clear();
- consumeToken();
- }
+ /// Whether an error occurred.
+ bool HadError = false;
- bool parseModuleMapFile();
-
- bool terminatedByDirective() { return false; }
- SourceLocation getLocation() { return Tok.getLocation(); }
- };
+ /// The active module.
+ Module *ActiveModule = nullptr;
+
+ /// Whether a module uses the 'requires excluded' hack to mark its
+ /// contents as 'textual'.
+ ///
+ /// On older Darwin SDK versions, 'requires excluded' is used to mark the
+ /// contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as
+ /// non-modular headers. For backwards compatibility, we continue to
+ /// support this idiom for just these modules, and map the headers to
+ /// 'textual' to match the original intent.
+ llvm::SmallPtrSet<Module *, 2> UsesRequiresExcludedHack;
+
+ void handleModuleDecl(const modulemap::ModuleDecl &MD);
+ void handleExternModuleDecl(const modulemap::ExternModuleDecl &EMD);
+ void handleRequiresDecl(const modulemap::RequiresDecl &RD);
+ void handleHeaderDecl(const modulemap::HeaderDecl &HD);
+ void handleUmbrellaDirDecl(const modulemap::UmbrellaDirDecl &UDD);
+ void handleExportDecl(const modulemap::ExportDecl &ED);
+ void handleExportAsDecl(const modulemap::ExportAsDecl &EAD);
+ void handleUseDecl(const modulemap::UseDecl &UD);
+ void handleLinkDecl(const modulemap::LinkDecl &LD);
+ void handleConfigMacros(const modulemap::ConfigMacrosDecl &CMD);
+ void handleConflict(const modulemap::ConflictDecl &CD);
+ void handleInferredModuleDecl(const modulemap::ModuleDecl &MD);
+
+ /// Private modules are canonicalized as Foo_Private. Clang provides extra
+ /// module map search logic to find the appropriate private module when PCH
+ /// is used with implicit module maps. Warn when private modules are written
+ /// in other ways (FooPrivate and Foo.Private), providing notes and fixits.
+ void diagnosePrivateModules(SourceLocation StartLoc);
+
+ using Attributes = ModuleMap::Attributes;
+
+public:
+ ModuleMapParser(modulemap::ModuleMapFile &MMF, SourceManager &SourceMgr,
+ DiagnosticsEngine &Diags, ModuleMap &Map, FileID ModuleMapFID,
+ DirectoryEntryRef Directory, bool IsSystem)
+ : MMF(MMF), SourceMgr(SourceMgr), Diags(Diags), Map(Map),
+ ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {}
+
+ bool parseModuleMapFile();
+};
} // namespace clang
-SourceLocation ModuleMapParser::consumeToken() {
- SourceLocation Result = Tok.getLocation();
-
-retry:
- Tok.clear();
- Token LToken;
- L.LexFromRawLexer(LToken);
- Tok.Location = LToken.getLocation().getRawEncoding();
- switch (LToken.getKind()) {
- case tok::raw_identifier: {
- StringRef RI = LToken.getRawIdentifier();
- Tok.StringData = RI.data();
- Tok.StringLength = RI.size();
- Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
- .Case("config_macros", MMToken::ConfigMacros)
- .Case("conflict", MMToken::Conflict)
- .Case("exclude", MMToken::ExcludeKeyword)
- .Case("explicit", MMToken::ExplicitKeyword)
- .Case("export", MMToken::ExportKeyword)
- .Case("export_as", MMToken::ExportAsKeyword)
- .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("textual", MMToken::TextualKeyword)
- .Case("umbrella", MMToken::UmbrellaKeyword)
- .Case("use", MMToken::UseKeyword)
- .Default(MMToken::Identifier);
- break;
- }
-
- case tok::comma:
- Tok.Kind = MMToken::Comma;
- break;
-
- case tok::eof:
- Tok.Kind = MMToken::EndOfFile;
- break;
-
- case tok::l_brace:
- Tok.Kind = MMToken::LBrace;
- break;
-
- case tok::l_square:
- Tok.Kind = MMToken::LSquare;
- break;
-
- case tok::period:
- Tok.Kind = MMToken::Period;
- break;
-
- case tok::r_brace:
- Tok.Kind = MMToken::RBrace;
- break;
-
- case tok::r_square:
- Tok.Kind = MMToken::RSquare;
- break;
-
- case tok::star:
- 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);
- HadError = true;
- goto retry;
- }
-
- // Parse the string literal.
- LangOptions LangOpts;
- StringLiteralParser StringLiteral(LToken, SourceMgr, LangOpts, *Target);
- if (StringLiteral.hadError)
- goto retry;
-
- // Copy the string literal into our string data allocator.
- unsigned Length = StringLiteral.GetStringLength();
- char *Saved = StringData.Allocate<char>(Length + 1);
- memcpy(Saved, StringLiteral.GetString().data(), Length);
- Saved[Length] = 0;
-
- // Form the token.
- Tok.Kind = MMToken::StringLiteral;
- Tok.StringData = Saved;
- Tok.StringLength = Length;
- break;
- }
-
- case tok::numeric_constant: {
- // We don't support any suffixes or other complications.
- SmallString<32> SpellingBuffer;
- SpellingBuffer.resize(LToken.getLength() + 1);
- const char *Start = SpellingBuffer.data();
- unsigned Length =
- Lexer::getSpelling(LToken, Start, SourceMgr, Map.LangOpts);
- uint64_t Value;
- if (StringRef(Start, Length).getAsInteger(0, Value)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
- HadError = true;
- goto retry;
- }
-
- Tok.Kind = MMToken::IntegerLiteral;
- Tok.IntegerValue = Value;
- break;
- }
-
- case tok::comment:
- goto retry;
-
- case tok::hash:
- // A module map can be terminated prematurely by
- // #pragma clang module contents
- // When building the module, we'll treat the rest of the file as the
- // contents of the module.
- {
- auto NextIsIdent = [&](StringRef Str) -> bool {
- L.LexFromRawLexer(LToken);
- return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
- LToken.getRawIdentifier() == Str;
- };
- if (NextIsIdent("pragma") && NextIsIdent("clang") &&
- NextIsIdent("module") && NextIsIdent("contents")) {
- Tok.Kind = MMToken::EndOfFile;
- break;
- }
- }
- [[fallthrough]];
-
- default:
- Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
- HadError = true;
- goto retry;
- }
-
- return Result;
-}
-
-void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
- unsigned braceDepth = 0;
- unsigned squareDepth = 0;
- do {
- switch (Tok.Kind) {
- case MMToken::EndOfFile:
- return;
-
- case MMToken::LBrace:
- if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
- return;
-
- ++braceDepth;
- break;
-
- case MMToken::LSquare:
- if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
- return;
-
- ++squareDepth;
- break;
-
- case MMToken::RBrace:
- if (braceDepth > 0)
- --braceDepth;
- else if (Tok.is(K))
- return;
- break;
-
- case MMToken::RSquare:
- if (squareDepth > 0)
- --squareDepth;
- else if (Tok.is(K))
- return;
- break;
-
- default:
- if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
- return;
- break;
- }
-
- consumeToken();
- } while (true);
-}
-
-/// Parse a module-id.
-///
-/// module-id:
-/// identifier
-/// identifier '.' module-id
-///
-/// \returns true if an error occurred, false otherwise.
-bool ModuleMapParser::parseModuleId(ModuleId &Id) {
- Id.clear();
- do {
- if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
- Id.push_back(
- std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
- consumeToken();
- } else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
- return true;
- }
-
- if (!Tok.is(MMToken::Period))
- break;
-
- consumeToken();
- } while (true);
-
- return false;
-}
-
-namespace {
-
- /// Enumerates the known attributes.
- enum AttributeKind {
- /// An unknown attribute.
- AT_unknown,
-
- /// The 'system' attribute.
- AT_system,
-
- /// The 'extern_c' attribute.
- AT_extern_c,
-
- /// The 'exhaustive' attribute.
- AT_exhaustive,
-
- /// The 'no_undeclared_includes' attribute.
- AT_no_undeclared_includes
- };
-
-} // namespace
-
/// Private modules are canonicalized as Foo_Private. Clang provides extra
/// module map search logic to find the appropriate private module when PCH
/// is used with implicit module maps. Warn when private modules are written
/// in other ways (FooPrivate and Foo.Private), providing notes and fixits.
-void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
- SourceLocation FrameworkLoc) {
+void ModuleMapParser::diagnosePrivateModules(SourceLocation StartLoc) {
auto GenNoteAndFixIt = [&](StringRef BadName, StringRef Canonical,
const Module *M, SourceRange ReplLoc) {
auto D = Diags.Report(ActiveModule->DefinitionLoc,
@@ -1902,12 +1560,10 @@ void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
<< FullName;
SourceLocation FixItInitBegin = CurrModuleDeclLoc;
- if (FrameworkLoc.isValid())
- FixItInitBegin = FrameworkLoc;
- if (ExplicitLoc.isValid())
- FixItInitBegin = ExplicitLoc;
+ if (StartLoc.isValid())
+ FixItInitBegin = StartLoc;
- if (FrameworkLoc.isValid() || ActiveModule->Parent->IsFramework)
+ if (ActiveModule->Parent->IsFramework)
FixedPrivModDecl.append("framework ");
FixedPrivModDecl.append("module ");
FixedPrivModDecl.append(Canonical);
@@ -1929,103 +1585,29 @@ void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
}
}
-/// Parse a module declaration.
-///
-/// module-declaration:
-/// 'extern' 'module' module-id string-literal
-/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
-/// { module-member* }
-///
-/// module-member:
-/// requires-declaration
-/// header-declaration
-/// submodule-declaration
-/// export-declaration
-/// export-as-declaration
-/// link-declaration
-///
-/// submodule-declaration:
-/// module-declaration
-/// inferred-submodule-declaration
-void ModuleMapParser::parseModuleDecl() {
- assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
- Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword));
- if (Tok.is(MMToken::ExternKeyword)) {
- parseExternModuleDecl();
- return;
- }
-
- // Parse 'explicit' or 'framework' keyword, if present.
- SourceLocation ExplicitLoc;
- SourceLocation FrameworkLoc;
- bool Explicit = false;
- bool Framework = false;
-
- // Parse 'explicit' keyword, if present.
- if (Tok.is(MMToken::ExplicitKeyword)) {
- ExplicitLoc = consumeToken();
- Explicit = true;
- }
-
- // Parse 'framework' keyword, if present.
- if (Tok.is(MMToken::FrameworkKeyword)) {
- FrameworkLoc = consumeToken();
- Framework = true;
- }
+void ModuleMapParser::handleModuleDecl(const modulemap::ModuleDecl &MD) {
+ if (MD.Id.front().first == "*")
+ return handleInferredModuleDecl(MD);
- // Parse 'module' keyword.
- if (!Tok.is(MMToken::ModuleKeyword)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
- consumeToken();
- HadError = true;
- return;
- }
- CurrModuleDeclLoc = consumeToken(); // 'module' keyword
-
- // If we have a wildcard for the module name, this is an inferred submodule.
- // Parse it.
- if (Tok.is(MMToken::Star))
- return parseInferredModuleDecl(Framework, Explicit);
-
- // Parse the module name.
- ModuleId Id;
- if (parseModuleId(Id)) {
- HadError = true;
- return;
- }
-
- if (ActiveModule) {
- if (Id.size() > 1) {
- Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
- << SourceRange(Id.front().second, Id.back().second);
-
- HadError = true;
- return;
- }
- } else if (Id.size() == 1 && Explicit) {
- // Top-level modules can't be explicit.
- Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
- Explicit = false;
- ExplicitLoc = SourceLocation();
- HadError = true;
- }
+ CurrModuleDeclLoc = MD.Location;
Module *PreviousActiveModule = ActiveModule;
- if (Id.size() > 1) {
+ if (MD.Id.size() > 1) {
// 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)) {
+ for (unsigned I = 0, N = MD.Id.size() - 1; I != N; ++I) {
+ if (Module *Next =
+ Map.lookupModuleQualified(MD.Id[I].first, ActiveModule)) {
if (I == 0)
TopLevelModule = Next;
ActiveModule = Next;
continue;
}
- Diags.Report(Id[I].second, diag::err_mmap_missing_parent_module)
- << Id[I].first << (ActiveModule != nullptr)
+ Diags.Report(MD.Id[I].second, diag::err_mmap_missing_parent_module)
+ << MD.Id[I].first << (ActiveModule != nullptr)
<< (ActiveModule
? ActiveModule->getTopLevelModule()->getFullModuleName()
: "");
@@ -2043,22 +1625,8 @@ void ModuleMapParser::parseModuleDecl() {
}
}
- StringRef ModuleName = Id.back().first;
- SourceLocation ModuleNameLoc = Id.back().second;
-
- // Parse the optional attribute list.
- Attributes Attrs;
- if (parseOptionalAttributes(Attrs))
- return;
-
- // Parse the opening brace.
- if (!Tok.is(MMToken::LBrace)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
- << ModuleName;
- HadError = true;
- return;
- }
- SourceLocation LBraceLoc = consumeToken();
+ StringRef ModuleName = MD.Id.back().first;
+ SourceLocation ModuleNameLoc = MD.Id.back().second;
// Determine whether this (sub)module has already been defined.
Module *ShadowingModule = nullptr;
@@ -2085,7 +1653,7 @@ void ModuleMapParser::parseModuleDecl() {
// that \c Existing is part of a framework iff the redefinition of FW
// we have just skipped had it too. Once we do that, stop checking
// the local framework qualifier and only rely on \c Existing.
- bool PartOfFramework = Framework || Existing->isPartOfFramework();
+ bool PartOfFramework = MD.Framework || Existing->isPartOfFramework();
// - If we're building a (preprocessed) module and we've just loaded the
// module map file from which it was created.
bool ParsedAsMainInput =
@@ -2096,14 +1664,6 @@ void ModuleMapParser::parseModuleDecl() {
if (LoadedFromASTFile || Inferred || PartOfFramework || ParsedAsMainInput) {
ActiveModule = PreviousActiveModule;
// Skip the module definition.
- skipUntil(MMToken::RBrace);
- if (Tok.is(MMToken::RBrace))
- consumeToken();
- else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
- Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
- HadError = true;
- }
return;
}
@@ -2114,12 +1674,6 @@ void ModuleMapParser::parseModuleDecl() {
Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
<< ModuleName;
Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
-
- // Skip the module definition.
- skipUntil(MMToken::RBrace);
- if (Tok.is(MMToken::RBrace))
- consumeToken();
-
HadError = true;
return;
}
@@ -2128,18 +1682,18 @@ void ModuleMapParser::parseModuleDecl() {
// Start defining this module.
if (ShadowingModule) {
ActiveModule =
- Map.createShadowedModule(ModuleName, Framework, ShadowingModule);
+ Map.createShadowedModule(ModuleName, MD.Framework, ShadowingModule);
} else {
ActiveModule = Map.findOrCreateModuleFirst(ModuleName, ActiveModule,
- Framework, Explicit);
+ MD.Framework, MD.Explicit);
}
ActiveModule->DefinitionLoc = ModuleNameLoc;
- if (Attrs.IsSystem || IsSystem)
+ if (MD.Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
- if (Attrs.IsExternC)
+ if (MD.Attrs.IsExternC)
ActiveModule->IsExternC = true;
- if (Attrs.NoUndeclaredIncludes)
+ if (MD.Attrs.NoUndeclaredIncludes)
ActiveModule->NoUndeclaredIncludes = true;
ActiveModule->Directory = Directory;
@@ -2161,89 +1715,34 @@ void ModuleMapParser::parseModuleDecl() {
!Diags.isIgnored(diag::warn_mmap_mismatched_private_module_name,
StartLoc) &&
ActiveModule->ModuleMapIsPrivate)
- diagnosePrivateModules(ExplicitLoc, FrameworkLoc);
-
- bool Done = false;
- do {
- switch (Tok.Kind) {
- case MMToken::EndOfFile:
- case MMToken::RBrace:
- Done = true;
- break;
-
- case MMToken::ConfigMacros:
- parseConfigMacros();
- break;
-
- case MMToken::Conflict:
- parseConflict();
- break;
-
- case MMToken::ExplicitKeyword:
- case MMToken::ExternKeyword:
- case MMToken::FrameworkKeyword:
- case MMToken::ModuleKeyword:
- parseModuleDecl();
- break;
-
- case MMToken::ExportKeyword:
- parseExportDecl();
- break;
-
- case MMToken::ExportAsKeyword:
- parseExportAsDecl();
- break;
-
- case MMToken::UseKeyword:
- parseUseDecl();
- break;
-
- case MMToken::RequiresKeyword:
- parseRequiresDecl();
- break;
-
- case MMToken::TextualKeyword:
- parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
- break;
-
- case MMToken::UmbrellaKeyword: {
- SourceLocation UmbrellaLoc = consumeToken();
- if (Tok.is(MMToken::HeaderKeyword))
- parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
- else
- parseUmbrellaDirDecl(UmbrellaLoc);
- break;
- }
-
- case MMToken::ExcludeKeyword:
- parseHeaderDecl(MMToken::ExcludeKeyword, consumeToken());
- break;
-
- case MMToken::PrivateKeyword:
- parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
- break;
-
- case MMToken::HeaderKeyword:
- parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
- break;
-
- case MMToken::LinkKeyword:
- parseLinkDecl();
- break;
-
- default:
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
- consumeToken();
- break;
- }
- } while (!Done);
-
- if (Tok.is(MMToken::RBrace))
- consumeToken();
- else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
- Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
- HadError = true;
+ diagnosePrivateModules(MD.Location);
+
+ for (const modulemap::Decl &Decl : MD.Decls) {
+ std::visit(
+ llvm::makeVisitor(
+ [&](const modulemap::RequiresDecl &RD) { handleRequiresDecl(RD); },
+ [&](const modulemap::HeaderDecl &HD) { handleHeaderDecl(HD); },
+ [&](const modulemap::UmbrellaDirDecl &UDD) {
+ handleUmbrellaDirDecl(UDD);
+ },
+ [&](const modulemap::ModuleDecl &MD) { handleModuleDecl(MD); },
+ [&](const modulemap::ExportDecl &ED) { handleExportDecl(ED); },
+ [&](const modulemap::ExportAsDecl &EAD) {
+ handleExportAsDecl(EAD);
+ },
+ [&](const modulemap::ExternModuleDecl &EMD) {
+ handleExternModuleDecl(EMD);
+ },
+ [&](const modulemap::UseDecl &UD) { handleUseDecl(UD); },
+ [&](const modulemap::LinkDecl &LD) { handleLinkDecl(LD); },
+ [&](const modulemap::ConfigMacrosDecl &CMD) {
+ handleConfigMacros(CMD);
+ },
+ [&](const modulemap::ConflictDecl &CD) { handleConflict(CD); },
+ [&](const modulemap::ExcludeDecl &ED) {
+ Diags.Report(ED.Location, diag::err_mmap_expected_member);
+ }),
+ Decl);
}
// If the active module is a top-level framework, and there are no link
@@ -2265,44 +1764,13 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule = PreviousActiveModule;
}
-/// Parse an extern module declaration.
-///
-/// extern module-declaration:
-/// 'extern' 'module' module-id string-literal
-void ModuleMapParser::parseExternModuleDecl() {
- assert(Tok.is(MMToken::ExternKeyword));
- SourceLocation ExternLoc = 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 = std::string(Tok.getString());
- consumeToken(); // filename
-
- StringRef FileNameRef = FileName;
+void ModuleMapParser::handleExternModuleDecl(
+ const modulemap::ExternModuleDecl &EMD) {
+ StringRef FileNameRef = EMD.Path;
SmallString<128> ModuleMapFileName;
if (llvm::sys::path::is_relative(FileNameRef)) {
ModuleMapFileName += Directory.getName();
- llvm::sys::path::append(ModuleMapFileName, FileName);
+ llvm::sys::path::append(ModuleMapFileName, EMD.Path);
FileNameRef = ModuleMapFileName;
}
if (auto File = SourceMgr.getFileManager().getOptionalFileRef(FileNameRef))
@@ -2311,7 +1779,7 @@ void ModuleMapParser::parseExternModuleDecl() {
Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
? Directory
: File->getDir(),
- FileID(), nullptr, ExternLoc);
+ FileID(), nullptr, EMD.Location);
}
/// Whether to add the requirement \p Feature to the module \p M.
@@ -2343,88 +1811,35 @@ static bool shouldAddRequirement(Module *M, StringRef Feature,
return true;
}
-/// Parse a requires declaration.
-///
-/// requires-declaration:
-/// 'requires' feature-list
-///
-/// feature-list:
-/// feature ',' feature-list
-/// feature
-///
-/// feature:
-/// '!'[opt] identifier
-void ModuleMapParser::parseRequiresDecl() {
- assert(Tok.is(MMToken::RequiresKeyword));
-
- // Parse 'requires' keyword.
- consumeToken();
-
- // 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;
- return;
- }
-
- // Consume the feature name.
- std::string Feature = std::string(Tok.getString());
- consumeToken();
+void ModuleMapParser::handleRequiresDecl(const modulemap::RequiresDecl &RD) {
+ for (const modulemap::RequiresFeature &RF : RD.Features) {
bool IsRequiresExcludedHack = false;
bool ShouldAddRequirement =
- shouldAddRequirement(ActiveModule, Feature, IsRequiresExcludedHack);
+ shouldAddRequirement(ActiveModule, RF.Feature, IsRequiresExcludedHack);
if (IsRequiresExcludedHack)
UsesRequiresExcludedHack.insert(ActiveModule);
if (ShouldAddRequirement) {
// Add this feature.
- ActiveModule->addRequirement(Feature, RequiredState, Map.LangOpts,
+ ActiveModule->addRequirement(RF.Feature, RF.RequiredState, Map.LangOpts,
*Map.Target);
}
-
- if (!Tok.is(MMToken::Comma))
- break;
-
- // Consume the comma.
- consumeToken();
- } while (true);
+ }
}
-/// Parse a header declaration.
-///
-/// header-declaration:
-/// 'textual'[opt] 'header' string-literal
-/// 'private' 'textual'[opt] 'header' string-literal
-/// 'exclude' 'header' string-literal
-/// 'umbrella' 'header' string-literal
-///
-/// FIXME: Support 'private textual header'.
-void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
- SourceLocation LeadingLoc) {
+void ModuleMapParser::handleHeaderDecl(const modulemap::HeaderDecl &HD) {
// We've already consumed the first token.
ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
- if (LeadingToken == MMToken::PrivateKeyword) {
+ if (HD.Private) {
Role = ModuleMap::PrivateHeader;
- // 'private' may optionally be followed by 'textual'.
- if (Tok.is(MMToken::TextualKeyword)) {
- LeadingToken = Tok.Kind;
- consumeToken();
- }
- } else if (LeadingToken == MMToken::ExcludeKeyword) {
+ } else if (HD.Excluded) {
Role = ModuleMap::ExcludedHeader;
}
- if (LeadingToken == MMToken::TextualKeyword)
+ if (HD.Textual)
Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
if (UsesRequiresExcludedHack.count(ActiveModule)) {
@@ -2433,28 +1848,10 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
}
- if (LeadingToken != MMToken::HeaderKeyword) {
- if (!Tok.is(MMToken::HeaderKeyword)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
- << (LeadingToken == MMToken::PrivateKeyword ? "private" :
- LeadingToken == MMToken::ExcludeKeyword ? "exclude" :
- LeadingToken == MMToken::TextualKeyword ? "textual" : "umbrella");
- return;
- }
- consumeToken();
- }
-
- // Parse the header name.
- if (!Tok.is(MMToken::StringLiteral)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
- << "header";
- HadError = true;
- return;
- }
Module::UnresolvedHeaderDirective Header;
- Header.FileName = std::string(Tok.getString());
- Header.FileNameLoc = consumeToken();
- Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
+ Header.FileName = HD.Path;
+ Header.FileNameLoc = HD.PathLoc;
+ Header.IsUmbrella = HD.Umbrella;
Header.Kind = Map.headerRoleToKind(Role);
// Check whether we already have an umbrella.
@@ -2466,60 +1863,10 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
return;
}
- // If we were given stat information, parse it so we can skip looking for
- // the file.
- if (Tok.is(MMToken::LBrace)) {
- SourceLocation LBraceLoc = consumeToken();
-
- while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
- enum Attribute { Size, ModTime, Unknown };
- StringRef Str = Tok.getString();
- SourceLocation Loc = consumeToken();
- switch (llvm::StringSwitch<Attribute>(Str)
- .Case("size", Size)
- .Case("mtime", ModTime)
- .Default(Unknown)) {
- case Size:
- if (Header.Size)
- Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
- if (!Tok.is(MMToken::IntegerLiteral)) {
- Diags.Report(Tok.getLocation(),
- diag::err_mmap_invalid_header_attribute_value) << Str;
- skipUntil(MMToken::RBrace);
- break;
- }
- Header.Size = Tok.getInteger();
- consumeToken();
- break;
-
- case ModTime:
- if (Header.ModTime)
- Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
- if (!Tok.is(MMToken::IntegerLiteral)) {
- Diags.Report(Tok.getLocation(),
- diag::err_mmap_invalid_header_attribute_value) << Str;
- skipUntil(MMToken::RBrace);
- break;
- }
- Header.ModTime = Tok.getInteger();
- consumeToken();
- break;
-
- case Unknown:
- Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
- skipUntil(MMToken::RBrace);
- break;
- }
- }
-
- if (Tok.is(MMToken::RBrace))
- consumeToken();
- else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
- Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
- HadError = true;
- }
- }
+ if (HD.Size)
+ Header.Size = HD.Size;
+ if (HD.MTime)
+ Header.ModTime = HD.MTime;
bool NeedsFramework = false;
// Don't add headers to the builtin modules if the builtin headers belong to
@@ -2541,27 +1888,15 @@ static bool compareModuleHeaders(const Module::Header &A,
return A.NameAsWritten < B.NameAsWritten;
}
-/// Parse an umbrella directory declaration.
-///
-/// umbrella-dir-declaration:
-/// umbrella string-literal
-void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
- // Parse the directory name.
- if (!Tok.is(MMToken::StringLiteral)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
- << "umbrella";
- HadError = true;
- return;
- }
-
- std::string DirName = std::string(Tok.getString());
+void ModuleMapParser::handleUmbrellaDirDecl(
+ const modulemap::UmbrellaDirDecl &UDD) {
+ std::string DirName = std::string(UDD.Path);
std::string DirNameAsWritten = DirName;
- SourceLocation DirNameLoc = consumeToken();
// Check whether we already have an umbrella.
if (!std::holds_alternative<std::monostate>(ActiveModule->Umbrella)) {
- Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)
- << ActiveModule->getFullModuleName();
+ Diags.Report(UDD.Location, diag::err_mmap_umbrella_clash)
+ << ActiveModule->getFullModuleName();
HadError = true;
return;
}
@@ -2578,8 +1913,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
if (!Dir) {
- Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)
- << DirName;
+ Diags.Report(UDD.Location, diag::warn_mmap_umbrella_dir_not_found)
+ << DirName;
return;
}
@@ -2609,8 +1944,8 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
}
if (Module *OwningModule = Map.UmbrellaDirs[*Dir]) {
- Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
- << OwningModule->getFullModuleName();
+ Diags.Report(UDD.Location, diag::err_mmap_umbrella_clash)
+ << OwningModule->getFullModuleName();
HadError = true;
return;
}
@@ -2619,521 +1954,169 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
Map.setUmbrellaDirAsWritten(ActiveModule, *Dir, DirNameAsWritten, DirName);
}
-/// Parse a module export declaration.
-///
-/// export-declaration:
-/// 'export' wildcard-module-id
-///
-/// wildcard-module-id:
-/// identifier
-/// '*'
-/// identifier '.' wildcard-module-id
-void ModuleMapParser::parseExportDecl() {
- assert(Tok.is(MMToken::ExportKeyword));
- SourceLocation ExportLoc = consumeToken();
-
- // Parse the module-id with an optional wildcard at the end.
- ModuleId ParsedModuleId;
- bool Wildcard = false;
- do {
- // FIXME: Support string-literal module names here.
- if (Tok.is(MMToken::Identifier)) {
- ParsedModuleId.push_back(
- std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
- consumeToken();
-
- if (Tok.is(MMToken::Period)) {
- consumeToken();
- continue;
- }
-
- break;
- }
-
- if(Tok.is(MMToken::Star)) {
- Wildcard = true;
- consumeToken();
- break;
- }
-
- Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
- HadError = true;
- return;
- } while (true);
-
- Module::UnresolvedExportDecl Unresolved = {
- ExportLoc, ParsedModuleId, Wildcard
- };
+void ModuleMapParser::handleExportDecl(const modulemap::ExportDecl &ED) {
+ Module::UnresolvedExportDecl Unresolved = {ED.Location, ED.Id, ED.Wildcard};
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-/// Parse a module export_as declaration.
-///
-/// export-as-declaration:
-/// 'export_as' identifier
-void ModuleMapParser::parseExportAsDecl() {
- assert(Tok.is(MMToken::ExportAsKeyword));
- consumeToken();
-
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
- HadError = true;
- return;
- }
-
- if (ActiveModule->Parent) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);
- consumeToken();
- return;
- }
+void ModuleMapParser::handleExportAsDecl(const modulemap::ExportAsDecl &EAD) {
+ auto ModName = EAD.Id.front();
if (!ActiveModule->ExportAsModule.empty()) {
- if (ActiveModule->ExportAsModule == Tok.getString()) {
- Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as)
- << ActiveModule->Name << Tok.getString();
+ if (ActiveModule->ExportAsModule == ModName.first) {
+ Diags.Report(ModName.second, diag::warn_mmap_redundant_export_as)
+ << ActiveModule->Name << ModName.first;
} else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as)
- << ActiveModule->Name << ActiveModule->ExportAsModule
- << Tok.getString();
+ Diags.Report(ModName.second, diag::err_mmap_conflicting_export_as)
+ << ActiveModule->Name << ActiveModule->ExportAsModule
+ << ModName.first;
}
}
- ActiveModule->ExportAsModule = std::string(Tok.getString());
+ ActiveModule->ExportAsModule = ModName.first;
Map.addLinkAsDependency(ActiveModule);
-
- consumeToken();
}
-/// Parse a module use declaration.
-///
-/// use-declaration:
-/// 'use' wildcard-module-id
-void ModuleMapParser::parseUseDecl() {
- assert(Tok.is(MMToken::UseKeyword));
- auto KWLoc = consumeToken();
- // Parse the module-id.
- ModuleId ParsedModuleId;
- parseModuleId(ParsedModuleId);
-
+void ModuleMapParser::handleUseDecl(const modulemap::UseDecl &UD) {
if (ActiveModule->Parent)
- Diags.Report(KWLoc, diag::err_mmap_use_decl_submodule);
+ Diags.Report(UD.Location, diag::err_mmap_use_decl_submodule);
else
- ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
+ ActiveModule->UnresolvedDirectUses.push_back(UD.Id);
}
-/// Parse a link declaration.
-///
-/// module-declaration:
-/// 'link' 'framework'[opt] string-literal
-void ModuleMapParser::parseLinkDecl() {
- assert(Tok.is(MMToken::LinkKeyword));
- SourceLocation LinkLoc = consumeToken();
-
- // Parse the optional 'framework' keyword.
- bool IsFramework = false;
- if (Tok.is(MMToken::FrameworkKeyword)) {
- consumeToken();
- IsFramework = true;
- }
-
- // Parse the library name
- if (!Tok.is(MMToken::StringLiteral)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
- << IsFramework << SourceRange(LinkLoc);
- HadError = true;
- return;
- }
-
- std::string LibraryName = std::string(Tok.getString());
- consumeToken();
- ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,
- IsFramework));
+void ModuleMapParser::handleLinkDecl(const modulemap::LinkDecl &LD) {
+ ActiveModule->LinkLibraries.push_back(
+ Module::LinkLibrary(std::string{LD.Library}, LD.Framework));
}
-/// Parse a configuration macro declaration.
-///
-/// module-declaration:
-/// 'config_macros' attributes[opt] config-macro-list?
-///
-/// config-macro-list:
-/// identifier (',' identifier)?
-void ModuleMapParser::parseConfigMacros() {
- assert(Tok.is(MMToken::ConfigMacros));
- SourceLocation ConfigMacrosLoc = consumeToken();
-
- // Only top-level modules can have configuration macros.
+void ModuleMapParser::handleConfigMacros(
+ const modulemap::ConfigMacrosDecl &CMD) {
if (ActiveModule->Parent) {
- Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);
- }
-
- // Parse the optional attributes.
- Attributes Attrs;
- if (parseOptionalAttributes(Attrs))
- return;
-
- if (Attrs.IsExhaustive && !ActiveModule->Parent) {
- ActiveModule->ConfigMacrosExhaustive = true;
- }
-
- // If we don't have an identifier, we're done.
- // FIXME: Support macros with the same name as a keyword here.
- if (!Tok.is(MMToken::Identifier))
+ Diags.Report(CMD.Location, diag::err_mmap_config_macro_submodule);
return;
-
- // Consume the first identifier.
- if (!ActiveModule->Parent) {
- ActiveModule->ConfigMacros.push_back(Tok.getString().str());
}
- consumeToken();
-
- do {
- // If there's a comma, consume it.
- if (!Tok.is(MMToken::Comma))
- break;
- consumeToken();
- // We expect to see a macro name here.
- // FIXME: Support macros with the same name as a keyword here.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
- break;
- }
-
- // Consume the macro name.
- if (!ActiveModule->Parent) {
- ActiveModule->ConfigMacros.push_back(Tok.getString().str());
- }
- consumeToken();
- } while (true);
-}
-
-/// Format a module-id into a string.
-static std::string formatModuleId(const ModuleId &Id) {
- std::string result;
- {
- llvm::raw_string_ostream OS(result);
-
- for (unsigned I = 0, N = Id.size(); I != N; ++I) {
- if (I)
- OS << ".";
- OS << Id[I].first;
- }
+ // TODO: Is this really the behavior we want for multiple config_macros
+ // declarations? If any of them are exhaustive then all of them are.
+ if (CMD.Exhaustive) {
+ ActiveModule->ConfigMacrosExhaustive = true;
}
-
- return result;
+ ActiveModule->ConfigMacros.insert(ActiveModule->ConfigMacros.end(),
+ CMD.Macros.begin(), CMD.Macros.end());
}
-/// Parse a conflict declaration.
-///
-/// module-declaration:
-/// 'conflict' module-id ',' string-literal
-void ModuleMapParser::parseConflict() {
- assert(Tok.is(MMToken::Conflict));
- SourceLocation ConflictLoc = consumeToken();
+void ModuleMapParser::handleConflict(const modulemap::ConflictDecl &CD) {
Module::UnresolvedConflict Conflict;
- // Parse the module-id.
- if (parseModuleId(Conflict.Id))
- return;
-
- // Parse the ','.
- if (!Tok.is(MMToken::Comma)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
- << SourceRange(ConflictLoc);
- return;
- }
- consumeToken();
+ Conflict.Id = CD.Id;
+ Conflict.Message = CD.Message;
- // Parse the message.
- if (!Tok.is(MMToken::StringLiteral)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
- << formatModuleId(Conflict.Id);
- return;
- }
- Conflict.Message = Tok.getString().str();
- consumeToken();
-
- // Add this unresolved conflict.
ActiveModule->UnresolvedConflicts.push_back(Conflict);
}
-/// Parse an inferred module declaration (wildcard modules).
-///
-/// module-declaration:
-/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
-/// { inferred-module-member* }
-///
-/// inferred-module-member:
-/// 'export' '*'
-/// 'exclude' identifier
-void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
- assert(Tok.is(MMToken::Star));
- SourceLocation StarLoc = consumeToken();
- bool Failed = false;
+void ModuleMapParser::handleInferredModuleDecl(
+ const modulemap::ModuleDecl &MD) {
+ SourceLocation StarLoc = MD.Id.front().second;
// Inferred modules must be submodules.
- if (!ActiveModule && !Framework) {
+ if (!ActiveModule && !MD.Framework) {
Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
- Failed = true;
+ return;
}
if (ActiveModule) {
// Inferred modules must have umbrella directories.
- if (!Failed && ActiveModule->IsAvailable &&
- !ActiveModule->getEffectiveUmbrellaDir()) {
+ if (ActiveModule->IsAvailable && !ActiveModule->getEffectiveUmbrellaDir()) {
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
- Failed = true;
+ return;
}
// Check for redefinition of an inferred module.
- if (!Failed && ActiveModule->InferSubmodules) {
+ if (ActiveModule->InferSubmodules) {
Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
if (ActiveModule->InferredSubmoduleLoc.isValid())
Diags.Report(ActiveModule->InferredSubmoduleLoc,
diag::note_mmap_prev_definition);
- Failed = true;
+ return;
}
// Check for the 'framework' keyword, which is not permitted here.
- if (Framework) {
+ if (MD.Framework) {
Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule);
- Framework = false;
+ return;
}
- } else if (Explicit) {
+ } else if (MD.Explicit) {
Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework);
- Explicit = false;
- }
-
- // If there were any problems with this inferred submodule, skip its body.
- if (Failed) {
- if (Tok.is(MMToken::LBrace)) {
- consumeToken();
- skipUntil(MMToken::RBrace);
- if (Tok.is(MMToken::RBrace))
- consumeToken();
- }
- HadError = true;
return;
}
- // Parse optional attributes.
- Attributes Attrs;
- if (parseOptionalAttributes(Attrs))
- return;
-
if (ActiveModule) {
// Note that we have an inferred submodule.
ActiveModule->InferSubmodules = true;
ActiveModule->InferredSubmoduleLoc = StarLoc;
- ActiveModule->InferExplicitSubmodules = Explicit;
+ ActiveModule->InferExplicitSubmodules = MD.Explicit;
} else {
// We'll be inferring framework modules for this directory.
auto &InfDir = Map.InferredDirectories[Directory];
InfDir.InferModules = true;
- InfDir.Attrs = Attrs;
+ InfDir.Attrs = MD.Attrs;
InfDir.ModuleMapFID = ModuleMapFID;
// FIXME: Handle the 'framework' keyword.
}
- // Parse the opening brace.
- if (!Tok.is(MMToken::LBrace)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
- HadError = true;
- return;
- }
- SourceLocation LBraceLoc = consumeToken();
-
- // Parse the body of the inferred submodule.
- bool Done = false;
- do {
- switch (Tok.Kind) {
- case MMToken::EndOfFile:
- case MMToken::RBrace:
- Done = true;
- break;
-
- case MMToken::ExcludeKeyword:
- if (ActiveModule) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
- << (ActiveModule != nullptr);
- consumeToken();
- break;
- }
-
- consumeToken();
- // FIXME: Support string-literal module names here.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
- break;
- }
-
- Map.InferredDirectories[Directory].ExcludedModules.push_back(
- std::string(Tok.getString()));
- consumeToken();
- break;
-
- case MMToken::ExportKeyword:
- if (!ActiveModule) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
- << (ActiveModule != nullptr);
- consumeToken();
- break;
- }
-
- consumeToken();
- if (Tok.is(MMToken::Star))
- ActiveModule->InferExportWildcard = true;
- else
- Diags.Report(Tok.getLocation(),
- diag::err_mmap_expected_export_wildcard);
- consumeToken();
- break;
-
- 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)
- << (ActiveModule != nullptr);
- consumeToken();
- break;
- }
- } while (!Done);
-
- if (Tok.is(MMToken::RBrace))
- consumeToken();
- else {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
- Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
- HadError = true;
+ for (const modulemap::Decl &Decl : MD.Decls) {
+ std::visit(
+ llvm::makeVisitor(
+ [&](const auto &Other) {
+ Diags.Report(Other.Location,
+ diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != nullptr);
+ },
+ [&](const modulemap::ExcludeDecl &ED) {
+ // Only inferred frameworks can have exclude decls
+ if (ActiveModule) {
+ Diags.Report(ED.Location,
+ diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != nullptr);
+ HadError = true;
+ return;
+ }
+ Map.InferredDirectories[Directory].ExcludedModules.emplace_back(
+ ED.Module);
+ },
+ [&](const modulemap::ExportDecl &ED) {
+ // Only inferred submodules can have export decls
+ if (!ActiveModule) {
+ Diags.Report(ED.Location,
+ diag::err_mmap_expected_inferred_member)
+ << (ActiveModule != nullptr);
+ HadError = true;
+ return;
+ }
+
+ if (ED.Wildcard && ED.Id.size() == 0)
+ ActiveModule->InferExportWildcard = true;
+ else
+ Diags.Report(ED.Id.front().second,
+ diag::err_mmap_expected_export_wildcard);
+ }),
+ Decl);
}
}
-/// Parse optional attributes.
-///
-/// attributes:
-/// attribute attributes
-/// attribute
-///
-/// attribute:
-/// [ identifier ]
-///
-/// \param Attrs Will be filled in with the parsed attributes.
-///
-/// \returns true if an error occurred, false otherwise.
-bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
- bool HadError = false;
-
- while (Tok.is(MMToken::LSquare)) {
- // Consume the '['.
- SourceLocation LSquareLoc = consumeToken();
-
- // Check whether we have an attribute name here.
- if (!Tok.is(MMToken::Identifier)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
- skipUntil(MMToken::RSquare);
- if (Tok.is(MMToken::RSquare))
- consumeToken();
- HadError = true;
- }
-
- // Decode the attribute name.
- AttributeKind Attribute
- = llvm::StringSwitch<AttributeKind>(Tok.getString())
- .Case("exhaustive", AT_exhaustive)
- .Case("extern_c", AT_extern_c)
- .Case("no_undeclared_includes", AT_no_undeclared_includes)
- .Case("system", AT_system)
- .Default(AT_unknown);
- switch (Attribute) {
- case AT_unknown:
- Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
- << Tok.getString();
- break;
-
- case AT_system:
- Attrs.IsSystem = true;
- break;
-
- case AT_extern_c:
- Attrs.IsExternC = true;
- break;
-
- case AT_exhaustive:
- Attrs.IsExhaustive = true;
- break;
-
- case AT_no_undeclared_includes:
- Attrs.NoUndeclaredIncludes = true;
- break;
- }
- consumeToken();
-
- // Consume the ']'.
- if (!Tok.is(MMToken::RSquare)) {
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
- Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
- skipUntil(MMToken::RSquare);
- HadError = true;
- }
-
- if (Tok.is(MMToken::RSquare))
- consumeToken();
+bool ModuleMapParser::parseModuleMapFile() {
+ for (const auto &Decl : MMF.Decls) {
+ std::visit(
+ llvm::makeVisitor(
+ [&](const modulemap::ModuleDecl &MD) { handleModuleDecl(MD); },
+ [&](const modulemap::ExternModuleDecl &EMD) {
+ handleExternModuleDecl(EMD);
+ }),
+ Decl);
}
-
return HadError;
}
-/// Parse a module map file.
-///
-/// module-map-file:
-/// module-declaration*
-bool ModuleMapParser::parseModuleMapFile() {
- do {
- switch (Tok.Kind) {
- case MMToken::EndOfFile:
- return HadError;
-
- case MMToken::ExplicitKeyword:
- case MMToken::ExternKeyword:
- case MMToken::ModuleKeyword:
- case MMToken::FrameworkKeyword:
- parseModuleDecl();
- break;
-
- case MMToken::Comma:
- case MMToken::ConfigMacros:
- case MMToken::Conflict:
- case MMToken::Exclaim:
- case MMToken::ExcludeKeyword:
- case MMToken::ExportKeyword:
- case MMToken::ExportAsKeyword:
- case MMToken::HeaderKeyword:
- case MMToken::Identifier:
- case MMToken::LBrace:
- 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::IntegerLiteral:
- case MMToken::TextualKeyword:
- case MMToken::UmbrellaKeyword:
- case MMToken::UseKeyword:
- Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
- HadError = true;
- consumeToken();
- break;
- }
- } while (true);
-}
-
bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,
DirectoryEntryRef Dir, FileID ID,
unsigned *Offset,
@@ -3158,25 +2141,18 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,
assert((!Offset || *Offset <= Buffer->getBufferSize()) &&
"invalid buffer offset");
- // Parse this module map file.
- Lexer L(SourceMgr.getLocForStartOfFile(ID), MMapLangOpts,
- Buffer->getBufferStart(),
- Buffer->getBufferStart() + (Offset ? *Offset : 0),
- Buffer->getBufferEnd());
- SourceLocation Start = L.getSourceLocation();
- ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem);
- bool Result = Parser.parseModuleMapFile();
- ParsedModuleMap[File] = Result;
-
- if (Offset) {
- auto Loc = SourceMgr.getDecomposedLoc(Parser.getLocation());
- assert(Loc.first == ID && "stopped in a different file?");
- *Offset = Loc.second;
+ std::optional<modulemap::ModuleMapFile> MMF =
+ modulemap::parseModuleMap(ID, Dir, SourceMgr, Diags, IsSystem, Offset);
+ bool Result = false;
+ if (MMF) {
+ ModuleMapParser Parser(*MMF, SourceMgr, Diags, *this, ID, Dir, IsSystem);
+ Result = Parser.parseModuleMapFile();
}
+ ParsedModuleMap[File] = Result;
// Notify callbacks that we parsed it.
for (const auto &Cb : Callbacks)
- Cb->moduleMapFileRead(Start, File, IsSystem);
+ Cb->moduleMapFileRead(MMF ? MMF->Start : SourceLocation(), File, IsSystem);
return Result;
}