xref: /freebsd/contrib/llvm-project/clang/lib/Lex/ModuleMapFile.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===- ModuleMapFile.cpp - ------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric ///
9*700637cbSDimitry Andric /// \file
10*700637cbSDimitry Andric /// This file handles parsing of modulemap files into a simple AST.
11*700637cbSDimitry Andric ///
12*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
13*700637cbSDimitry Andric 
14*700637cbSDimitry Andric #include "clang/Lex/ModuleMapFile.h"
15*700637cbSDimitry Andric #include "clang/Basic/Diagnostic.h"
16*700637cbSDimitry Andric #include "clang/Basic/LangOptions.h"
17*700637cbSDimitry Andric #include "clang/Basic/Module.h"
18*700637cbSDimitry Andric #include "clang/Basic/SourceManager.h"
19*700637cbSDimitry Andric #include "clang/Lex/LexDiagnostic.h"
20*700637cbSDimitry Andric #include "clang/Lex/Lexer.h"
21*700637cbSDimitry Andric #include "clang/Lex/ModuleMap.h"
22*700637cbSDimitry Andric #include "llvm/ADT/STLExtras.h"
23*700637cbSDimitry Andric #include <optional>
24*700637cbSDimitry Andric 
25*700637cbSDimitry Andric using namespace clang;
26*700637cbSDimitry Andric using namespace modulemap;
27*700637cbSDimitry Andric 
28*700637cbSDimitry Andric namespace {
29*700637cbSDimitry Andric struct MMToken {
30*700637cbSDimitry Andric   enum TokenKind {
31*700637cbSDimitry Andric     Comma,
32*700637cbSDimitry Andric     ConfigMacros,
33*700637cbSDimitry Andric     Conflict,
34*700637cbSDimitry Andric     EndOfFile,
35*700637cbSDimitry Andric     HeaderKeyword,
36*700637cbSDimitry Andric     Identifier,
37*700637cbSDimitry Andric     Exclaim,
38*700637cbSDimitry Andric     ExcludeKeyword,
39*700637cbSDimitry Andric     ExplicitKeyword,
40*700637cbSDimitry Andric     ExportKeyword,
41*700637cbSDimitry Andric     ExportAsKeyword,
42*700637cbSDimitry Andric     ExternKeyword,
43*700637cbSDimitry Andric     FrameworkKeyword,
44*700637cbSDimitry Andric     LinkKeyword,
45*700637cbSDimitry Andric     ModuleKeyword,
46*700637cbSDimitry Andric     Period,
47*700637cbSDimitry Andric     PrivateKeyword,
48*700637cbSDimitry Andric     UmbrellaKeyword,
49*700637cbSDimitry Andric     UseKeyword,
50*700637cbSDimitry Andric     RequiresKeyword,
51*700637cbSDimitry Andric     Star,
52*700637cbSDimitry Andric     StringLiteral,
53*700637cbSDimitry Andric     IntegerLiteral,
54*700637cbSDimitry Andric     TextualKeyword,
55*700637cbSDimitry Andric     LBrace,
56*700637cbSDimitry Andric     RBrace,
57*700637cbSDimitry Andric     LSquare,
58*700637cbSDimitry Andric     RSquare
59*700637cbSDimitry Andric   } Kind;
60*700637cbSDimitry Andric 
61*700637cbSDimitry Andric   SourceLocation::UIntTy Location;
62*700637cbSDimitry Andric   unsigned StringLength;
63*700637cbSDimitry Andric   union {
64*700637cbSDimitry Andric     // If Kind != IntegerLiteral.
65*700637cbSDimitry Andric     const char *StringData;
66*700637cbSDimitry Andric 
67*700637cbSDimitry Andric     // If Kind == IntegerLiteral.
68*700637cbSDimitry Andric     uint64_t IntegerValue;
69*700637cbSDimitry Andric   };
70*700637cbSDimitry Andric 
clear__anon5501bfd60111::MMToken71*700637cbSDimitry Andric   void clear() {
72*700637cbSDimitry Andric     Kind = EndOfFile;
73*700637cbSDimitry Andric     Location = 0;
74*700637cbSDimitry Andric     StringLength = 0;
75*700637cbSDimitry Andric     StringData = nullptr;
76*700637cbSDimitry Andric   }
77*700637cbSDimitry Andric 
is__anon5501bfd60111::MMToken78*700637cbSDimitry Andric   bool is(TokenKind K) const { return Kind == K; }
79*700637cbSDimitry Andric 
getLocation__anon5501bfd60111::MMToken80*700637cbSDimitry Andric   SourceLocation getLocation() const {
81*700637cbSDimitry Andric     return SourceLocation::getFromRawEncoding(Location);
82*700637cbSDimitry Andric   }
83*700637cbSDimitry Andric 
getInteger__anon5501bfd60111::MMToken84*700637cbSDimitry Andric   uint64_t getInteger() const {
85*700637cbSDimitry Andric     return Kind == IntegerLiteral ? IntegerValue : 0;
86*700637cbSDimitry Andric   }
87*700637cbSDimitry Andric 
getString__anon5501bfd60111::MMToken88*700637cbSDimitry Andric   StringRef getString() const {
89*700637cbSDimitry Andric     return Kind == IntegerLiteral ? StringRef()
90*700637cbSDimitry Andric                                   : StringRef(StringData, StringLength);
91*700637cbSDimitry Andric   }
92*700637cbSDimitry Andric };
93*700637cbSDimitry Andric 
94*700637cbSDimitry Andric struct ModuleMapFileParser {
95*700637cbSDimitry Andric   // External context
96*700637cbSDimitry Andric   Lexer &L;
97*700637cbSDimitry Andric   DiagnosticsEngine &Diags;
98*700637cbSDimitry Andric 
99*700637cbSDimitry Andric   /// Parsed representation of the module map file
100*700637cbSDimitry Andric   ModuleMapFile MMF{};
101*700637cbSDimitry Andric 
102*700637cbSDimitry Andric   bool HadError = false;
103*700637cbSDimitry Andric 
104*700637cbSDimitry Andric   /// The current token.
105*700637cbSDimitry Andric   MMToken Tok{};
106*700637cbSDimitry Andric 
107*700637cbSDimitry Andric   bool parseTopLevelDecls();
108*700637cbSDimitry Andric   std::optional<ModuleDecl> parseModuleDecl(bool TopLevel);
109*700637cbSDimitry Andric   std::optional<ExternModuleDecl> parseExternModuleDecl();
110*700637cbSDimitry Andric   std::optional<ConfigMacrosDecl> parseConfigMacrosDecl();
111*700637cbSDimitry Andric   std::optional<ConflictDecl> parseConflictDecl();
112*700637cbSDimitry Andric   std::optional<ExportDecl> parseExportDecl();
113*700637cbSDimitry Andric   std::optional<ExportAsDecl> parseExportAsDecl();
114*700637cbSDimitry Andric   std::optional<UseDecl> parseUseDecl();
115*700637cbSDimitry Andric   std::optional<RequiresDecl> parseRequiresDecl();
116*700637cbSDimitry Andric   std::optional<HeaderDecl> parseHeaderDecl(MMToken::TokenKind LeadingToken,
117*700637cbSDimitry Andric                                             SourceLocation LeadingLoc);
118*700637cbSDimitry Andric   std::optional<ExcludeDecl> parseExcludeDecl(clang::SourceLocation LeadingLoc);
119*700637cbSDimitry Andric   std::optional<UmbrellaDirDecl>
120*700637cbSDimitry Andric   parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
121*700637cbSDimitry Andric   std::optional<LinkDecl> parseLinkDecl();
122*700637cbSDimitry Andric 
123*700637cbSDimitry Andric   SourceLocation consumeToken();
124*700637cbSDimitry Andric   void skipUntil(MMToken::TokenKind K);
125*700637cbSDimitry Andric   bool parseModuleId(ModuleId &Id);
126*700637cbSDimitry Andric   bool parseOptionalAttributes(ModuleAttributes &Attrs);
127*700637cbSDimitry Andric 
getLocation__anon5501bfd60111::ModuleMapFileParser128*700637cbSDimitry Andric   SourceLocation getLocation() const { return Tok.getLocation(); };
129*700637cbSDimitry Andric };
130*700637cbSDimitry Andric 
formatModuleId(const ModuleId & Id)131*700637cbSDimitry Andric std::string formatModuleId(const ModuleId &Id) {
132*700637cbSDimitry Andric   std::string result;
133*700637cbSDimitry Andric   {
134*700637cbSDimitry Andric     llvm::raw_string_ostream OS(result);
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric     for (unsigned I = 0, N = Id.size(); I != N; ++I) {
137*700637cbSDimitry Andric       if (I)
138*700637cbSDimitry Andric         OS << ".";
139*700637cbSDimitry Andric       OS << Id[I].first;
140*700637cbSDimitry Andric     }
141*700637cbSDimitry Andric   }
142*700637cbSDimitry Andric 
143*700637cbSDimitry Andric   return result;
144*700637cbSDimitry Andric }
145*700637cbSDimitry Andric } // end anonymous namespace
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric std::optional<ModuleMapFile>
parseModuleMap(FileID ID,clang::DirectoryEntryRef Dir,SourceManager & SM,DiagnosticsEngine & Diags,bool IsSystem,unsigned * Offset)148*700637cbSDimitry Andric modulemap::parseModuleMap(FileID ID, clang::DirectoryEntryRef Dir,
149*700637cbSDimitry Andric                           SourceManager &SM, DiagnosticsEngine &Diags,
150*700637cbSDimitry Andric                           bool IsSystem, unsigned *Offset) {
151*700637cbSDimitry Andric   std::optional<llvm::MemoryBufferRef> Buffer = SM.getBufferOrNone(ID);
152*700637cbSDimitry Andric   LangOptions LOpts;
153*700637cbSDimitry Andric   LOpts.LangStd = clang::LangStandard::lang_c99;
154*700637cbSDimitry Andric   Lexer L(SM.getLocForStartOfFile(ID), LOpts, Buffer->getBufferStart(),
155*700637cbSDimitry Andric           Buffer->getBufferStart() + (Offset ? *Offset : 0),
156*700637cbSDimitry Andric           Buffer->getBufferEnd());
157*700637cbSDimitry Andric   SourceLocation Start = L.getSourceLocation();
158*700637cbSDimitry Andric 
159*700637cbSDimitry Andric   ModuleMapFileParser Parser{L, Diags};
160*700637cbSDimitry Andric   bool Failed = Parser.parseTopLevelDecls();
161*700637cbSDimitry Andric 
162*700637cbSDimitry Andric   if (Offset) {
163*700637cbSDimitry Andric     auto Loc = SM.getDecomposedLoc(Parser.getLocation());
164*700637cbSDimitry Andric     assert(Loc.first == ID && "stopped in a different file?");
165*700637cbSDimitry Andric     *Offset = Loc.second;
166*700637cbSDimitry Andric   }
167*700637cbSDimitry Andric 
168*700637cbSDimitry Andric   if (Failed)
169*700637cbSDimitry Andric     return std::nullopt;
170*700637cbSDimitry Andric   Parser.MMF.ID = ID;
171*700637cbSDimitry Andric   Parser.MMF.Dir = Dir;
172*700637cbSDimitry Andric   Parser.MMF.Start = Start;
173*700637cbSDimitry Andric   Parser.MMF.IsSystem = IsSystem;
174*700637cbSDimitry Andric   return std::move(Parser.MMF);
175*700637cbSDimitry Andric }
176*700637cbSDimitry Andric 
parseTopLevelDecls()177*700637cbSDimitry Andric bool ModuleMapFileParser::parseTopLevelDecls() {
178*700637cbSDimitry Andric   Tok.clear();
179*700637cbSDimitry Andric   consumeToken();
180*700637cbSDimitry Andric   do {
181*700637cbSDimitry Andric     switch (Tok.Kind) {
182*700637cbSDimitry Andric     case MMToken::EndOfFile:
183*700637cbSDimitry Andric       return HadError;
184*700637cbSDimitry Andric     case MMToken::ExternKeyword: {
185*700637cbSDimitry Andric       std::optional<ExternModuleDecl> EMD = parseExternModuleDecl();
186*700637cbSDimitry Andric       if (EMD)
187*700637cbSDimitry Andric         MMF.Decls.push_back(std::move(*EMD));
188*700637cbSDimitry Andric       break;
189*700637cbSDimitry Andric     }
190*700637cbSDimitry Andric     case MMToken::ExplicitKeyword:
191*700637cbSDimitry Andric     case MMToken::ModuleKeyword:
192*700637cbSDimitry Andric     case MMToken::FrameworkKeyword: {
193*700637cbSDimitry Andric       std::optional<ModuleDecl> MD = parseModuleDecl(true);
194*700637cbSDimitry Andric       if (MD)
195*700637cbSDimitry Andric         MMF.Decls.push_back(std::move(*MD));
196*700637cbSDimitry Andric       break;
197*700637cbSDimitry Andric     }
198*700637cbSDimitry Andric     case MMToken::Comma:
199*700637cbSDimitry Andric     case MMToken::ConfigMacros:
200*700637cbSDimitry Andric     case MMToken::Conflict:
201*700637cbSDimitry Andric     case MMToken::Exclaim:
202*700637cbSDimitry Andric     case MMToken::ExcludeKeyword:
203*700637cbSDimitry Andric     case MMToken::ExportKeyword:
204*700637cbSDimitry Andric     case MMToken::ExportAsKeyword:
205*700637cbSDimitry Andric     case MMToken::HeaderKeyword:
206*700637cbSDimitry Andric     case MMToken::Identifier:
207*700637cbSDimitry Andric     case MMToken::LBrace:
208*700637cbSDimitry Andric     case MMToken::LinkKeyword:
209*700637cbSDimitry Andric     case MMToken::LSquare:
210*700637cbSDimitry Andric     case MMToken::Period:
211*700637cbSDimitry Andric     case MMToken::PrivateKeyword:
212*700637cbSDimitry Andric     case MMToken::RBrace:
213*700637cbSDimitry Andric     case MMToken::RSquare:
214*700637cbSDimitry Andric     case MMToken::RequiresKeyword:
215*700637cbSDimitry Andric     case MMToken::Star:
216*700637cbSDimitry Andric     case MMToken::StringLiteral:
217*700637cbSDimitry Andric     case MMToken::IntegerLiteral:
218*700637cbSDimitry Andric     case MMToken::TextualKeyword:
219*700637cbSDimitry Andric     case MMToken::UmbrellaKeyword:
220*700637cbSDimitry Andric     case MMToken::UseKeyword:
221*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
222*700637cbSDimitry Andric       HadError = true;
223*700637cbSDimitry Andric       consumeToken();
224*700637cbSDimitry Andric       break;
225*700637cbSDimitry Andric     }
226*700637cbSDimitry Andric   } while (true);
227*700637cbSDimitry Andric }
228*700637cbSDimitry Andric 
229*700637cbSDimitry Andric /// Parse a module declaration.
230*700637cbSDimitry Andric ///
231*700637cbSDimitry Andric ///   module-declaration:
232*700637cbSDimitry Andric ///     'extern' 'module' module-id string-literal
233*700637cbSDimitry Andric ///     'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
234*700637cbSDimitry Andric ///       { module-member* }
235*700637cbSDimitry Andric ///
236*700637cbSDimitry Andric ///   module-member:
237*700637cbSDimitry Andric ///     requires-declaration
238*700637cbSDimitry Andric ///     header-declaration
239*700637cbSDimitry Andric ///     submodule-declaration
240*700637cbSDimitry Andric ///     export-declaration
241*700637cbSDimitry Andric ///     export-as-declaration
242*700637cbSDimitry Andric ///     link-declaration
243*700637cbSDimitry Andric ///
244*700637cbSDimitry Andric ///   submodule-declaration:
245*700637cbSDimitry Andric ///     module-declaration
246*700637cbSDimitry Andric ///     inferred-submodule-declaration
parseModuleDecl(bool TopLevel)247*700637cbSDimitry Andric std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(bool TopLevel) {
248*700637cbSDimitry Andric   assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
249*700637cbSDimitry Andric          Tok.is(MMToken::FrameworkKeyword));
250*700637cbSDimitry Andric 
251*700637cbSDimitry Andric   ModuleDecl MDecl;
252*700637cbSDimitry Andric 
253*700637cbSDimitry Andric   SourceLocation ExplicitLoc;
254*700637cbSDimitry Andric   MDecl.Explicit = false;
255*700637cbSDimitry Andric   MDecl.Framework = false;
256*700637cbSDimitry Andric 
257*700637cbSDimitry Andric   // Parse 'explicit' keyword, if present.
258*700637cbSDimitry Andric   if (Tok.is(MMToken::ExplicitKeyword)) {
259*700637cbSDimitry Andric     MDecl.Location = ExplicitLoc = consumeToken();
260*700637cbSDimitry Andric     MDecl.Explicit = true;
261*700637cbSDimitry Andric   }
262*700637cbSDimitry Andric 
263*700637cbSDimitry Andric   // Parse 'framework' keyword, if present.
264*700637cbSDimitry Andric   if (Tok.is(MMToken::FrameworkKeyword)) {
265*700637cbSDimitry Andric     SourceLocation FrameworkLoc = consumeToken();
266*700637cbSDimitry Andric     if (!MDecl.Location.isValid())
267*700637cbSDimitry Andric       MDecl.Location = FrameworkLoc;
268*700637cbSDimitry Andric     MDecl.Framework = true;
269*700637cbSDimitry Andric   }
270*700637cbSDimitry Andric 
271*700637cbSDimitry Andric   // Parse 'module' keyword.
272*700637cbSDimitry Andric   if (!Tok.is(MMToken::ModuleKeyword)) {
273*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
274*700637cbSDimitry Andric     consumeToken();
275*700637cbSDimitry Andric     HadError = true;
276*700637cbSDimitry Andric     return std::nullopt;
277*700637cbSDimitry Andric   }
278*700637cbSDimitry Andric   SourceLocation ModuleLoc = consumeToken();
279*700637cbSDimitry Andric   if (!MDecl.Location.isValid())
280*700637cbSDimitry Andric     MDecl.Location = ModuleLoc; // 'module' keyword
281*700637cbSDimitry Andric 
282*700637cbSDimitry Andric   // If we have a wildcard for the module name, this is an inferred submodule.
283*700637cbSDimitry Andric   // We treat it as a normal module at this point.
284*700637cbSDimitry Andric   if (Tok.is(MMToken::Star)) {
285*700637cbSDimitry Andric     SourceLocation StarLoc = consumeToken();
286*700637cbSDimitry Andric     MDecl.Id.push_back({"*", StarLoc});
287*700637cbSDimitry Andric     if (TopLevel && !MDecl.Framework) {
288*700637cbSDimitry Andric       Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
289*700637cbSDimitry Andric       HadError = true;
290*700637cbSDimitry Andric       return std::nullopt;
291*700637cbSDimitry Andric     }
292*700637cbSDimitry Andric   } else {
293*700637cbSDimitry Andric     // Parse the module name.
294*700637cbSDimitry Andric     if (parseModuleId(MDecl.Id)) {
295*700637cbSDimitry Andric       HadError = true;
296*700637cbSDimitry Andric       return std::nullopt;
297*700637cbSDimitry Andric     }
298*700637cbSDimitry Andric     if (!TopLevel) {
299*700637cbSDimitry Andric       if (MDecl.Id.size() > 1) {
300*700637cbSDimitry Andric         Diags.Report(MDecl.Id.front().second,
301*700637cbSDimitry Andric                      diag::err_mmap_nested_submodule_id)
302*700637cbSDimitry Andric             << SourceRange(MDecl.Id.front().second, MDecl.Id.back().second);
303*700637cbSDimitry Andric 
304*700637cbSDimitry Andric         HadError = true;
305*700637cbSDimitry Andric       }
306*700637cbSDimitry Andric     } else if (MDecl.Id.size() == 1 && MDecl.Explicit) {
307*700637cbSDimitry Andric       // Top-level modules can't be explicit.
308*700637cbSDimitry Andric       Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
309*700637cbSDimitry Andric       MDecl.Explicit = false;
310*700637cbSDimitry Andric       HadError = true;
311*700637cbSDimitry Andric     }
312*700637cbSDimitry Andric   }
313*700637cbSDimitry Andric 
314*700637cbSDimitry Andric   // Parse the optional attribute list.
315*700637cbSDimitry Andric   if (parseOptionalAttributes(MDecl.Attrs))
316*700637cbSDimitry Andric     return std::nullopt;
317*700637cbSDimitry Andric 
318*700637cbSDimitry Andric   // Parse the opening brace.
319*700637cbSDimitry Andric   if (!Tok.is(MMToken::LBrace)) {
320*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
321*700637cbSDimitry Andric         << MDecl.Id.back().first;
322*700637cbSDimitry Andric     HadError = true;
323*700637cbSDimitry Andric     return std::nullopt;
324*700637cbSDimitry Andric   }
325*700637cbSDimitry Andric   SourceLocation LBraceLoc = consumeToken();
326*700637cbSDimitry Andric 
327*700637cbSDimitry Andric   bool Done = false;
328*700637cbSDimitry Andric   do {
329*700637cbSDimitry Andric     std::optional<Decl> SubDecl;
330*700637cbSDimitry Andric     switch (Tok.Kind) {
331*700637cbSDimitry Andric     case MMToken::EndOfFile:
332*700637cbSDimitry Andric     case MMToken::RBrace:
333*700637cbSDimitry Andric       Done = true;
334*700637cbSDimitry Andric       break;
335*700637cbSDimitry Andric 
336*700637cbSDimitry Andric     case MMToken::ConfigMacros:
337*700637cbSDimitry Andric       // Only top-level modules can have configuration macros.
338*700637cbSDimitry Andric       if (!TopLevel)
339*700637cbSDimitry Andric         Diags.Report(Tok.getLocation(), diag::err_mmap_config_macro_submodule);
340*700637cbSDimitry Andric       SubDecl = parseConfigMacrosDecl();
341*700637cbSDimitry Andric       break;
342*700637cbSDimitry Andric 
343*700637cbSDimitry Andric     case MMToken::Conflict:
344*700637cbSDimitry Andric       SubDecl = parseConflictDecl();
345*700637cbSDimitry Andric       break;
346*700637cbSDimitry Andric 
347*700637cbSDimitry Andric     case MMToken::ExternKeyword:
348*700637cbSDimitry Andric       SubDecl = parseExternModuleDecl();
349*700637cbSDimitry Andric       break;
350*700637cbSDimitry Andric 
351*700637cbSDimitry Andric     case MMToken::ExplicitKeyword:
352*700637cbSDimitry Andric     case MMToken::FrameworkKeyword:
353*700637cbSDimitry Andric     case MMToken::ModuleKeyword:
354*700637cbSDimitry Andric       SubDecl = parseModuleDecl(false);
355*700637cbSDimitry Andric       break;
356*700637cbSDimitry Andric 
357*700637cbSDimitry Andric     case MMToken::ExportKeyword:
358*700637cbSDimitry Andric       SubDecl = parseExportDecl();
359*700637cbSDimitry Andric       break;
360*700637cbSDimitry Andric 
361*700637cbSDimitry Andric     case MMToken::ExportAsKeyword:
362*700637cbSDimitry Andric       if (!TopLevel) {
363*700637cbSDimitry Andric         Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);
364*700637cbSDimitry Andric         parseExportAsDecl();
365*700637cbSDimitry Andric       } else
366*700637cbSDimitry Andric         SubDecl = parseExportAsDecl();
367*700637cbSDimitry Andric       break;
368*700637cbSDimitry Andric 
369*700637cbSDimitry Andric     case MMToken::UseKeyword:
370*700637cbSDimitry Andric       SubDecl = parseUseDecl();
371*700637cbSDimitry Andric       break;
372*700637cbSDimitry Andric 
373*700637cbSDimitry Andric     case MMToken::RequiresKeyword:
374*700637cbSDimitry Andric       SubDecl = parseRequiresDecl();
375*700637cbSDimitry Andric       break;
376*700637cbSDimitry Andric 
377*700637cbSDimitry Andric     case MMToken::TextualKeyword:
378*700637cbSDimitry Andric       SubDecl = parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
379*700637cbSDimitry Andric       break;
380*700637cbSDimitry Andric 
381*700637cbSDimitry Andric     case MMToken::UmbrellaKeyword: {
382*700637cbSDimitry Andric       SourceLocation UmbrellaLoc = consumeToken();
383*700637cbSDimitry Andric       if (Tok.is(MMToken::HeaderKeyword))
384*700637cbSDimitry Andric         SubDecl = parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
385*700637cbSDimitry Andric       else
386*700637cbSDimitry Andric         SubDecl = parseUmbrellaDirDecl(UmbrellaLoc);
387*700637cbSDimitry Andric       break;
388*700637cbSDimitry Andric     }
389*700637cbSDimitry Andric 
390*700637cbSDimitry Andric     case MMToken::ExcludeKeyword: {
391*700637cbSDimitry Andric       SourceLocation ExcludeLoc = consumeToken();
392*700637cbSDimitry Andric       if (Tok.is(MMToken::HeaderKeyword))
393*700637cbSDimitry Andric         SubDecl = parseHeaderDecl(MMToken::ExcludeKeyword, ExcludeLoc);
394*700637cbSDimitry Andric       else
395*700637cbSDimitry Andric         SubDecl = parseExcludeDecl(ExcludeLoc);
396*700637cbSDimitry Andric       break;
397*700637cbSDimitry Andric     }
398*700637cbSDimitry Andric 
399*700637cbSDimitry Andric     case MMToken::PrivateKeyword:
400*700637cbSDimitry Andric       SubDecl = parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
401*700637cbSDimitry Andric       break;
402*700637cbSDimitry Andric 
403*700637cbSDimitry Andric     case MMToken::HeaderKeyword:
404*700637cbSDimitry Andric       SubDecl = parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
405*700637cbSDimitry Andric       break;
406*700637cbSDimitry Andric 
407*700637cbSDimitry Andric     case MMToken::LinkKeyword:
408*700637cbSDimitry Andric       SubDecl = parseLinkDecl();
409*700637cbSDimitry Andric       break;
410*700637cbSDimitry Andric 
411*700637cbSDimitry Andric     default:
412*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
413*700637cbSDimitry Andric       consumeToken();
414*700637cbSDimitry Andric       break;
415*700637cbSDimitry Andric     }
416*700637cbSDimitry Andric     if (SubDecl)
417*700637cbSDimitry Andric       MDecl.Decls.push_back(std::move(*SubDecl));
418*700637cbSDimitry Andric   } while (!Done);
419*700637cbSDimitry Andric 
420*700637cbSDimitry Andric   if (Tok.is(MMToken::RBrace))
421*700637cbSDimitry Andric     consumeToken();
422*700637cbSDimitry Andric   else {
423*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
424*700637cbSDimitry Andric     Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
425*700637cbSDimitry Andric     HadError = true;
426*700637cbSDimitry Andric   }
427*700637cbSDimitry Andric   return std::move(MDecl);
428*700637cbSDimitry Andric }
429*700637cbSDimitry Andric 
parseExternModuleDecl()430*700637cbSDimitry Andric std::optional<ExternModuleDecl> ModuleMapFileParser::parseExternModuleDecl() {
431*700637cbSDimitry Andric   assert(Tok.is(MMToken::ExternKeyword));
432*700637cbSDimitry Andric   ExternModuleDecl EMD;
433*700637cbSDimitry Andric   EMD.Location = consumeToken(); // 'extern' keyword
434*700637cbSDimitry Andric 
435*700637cbSDimitry Andric   // Parse 'module' keyword.
436*700637cbSDimitry Andric   if (!Tok.is(MMToken::ModuleKeyword)) {
437*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
438*700637cbSDimitry Andric     consumeToken();
439*700637cbSDimitry Andric     HadError = true;
440*700637cbSDimitry Andric     return std::nullopt;
441*700637cbSDimitry Andric   }
442*700637cbSDimitry Andric   consumeToken(); // 'module' keyword
443*700637cbSDimitry Andric 
444*700637cbSDimitry Andric   // Parse the module name.
445*700637cbSDimitry Andric   if (parseModuleId(EMD.Id)) {
446*700637cbSDimitry Andric     HadError = true;
447*700637cbSDimitry Andric     return std::nullopt;
448*700637cbSDimitry Andric   }
449*700637cbSDimitry Andric 
450*700637cbSDimitry Andric   // Parse the referenced module map file name.
451*700637cbSDimitry Andric   if (!Tok.is(MMToken::StringLiteral)) {
452*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);
453*700637cbSDimitry Andric     HadError = true;
454*700637cbSDimitry Andric     return std::nullopt;
455*700637cbSDimitry Andric   }
456*700637cbSDimitry Andric   EMD.Path = Tok.getString();
457*700637cbSDimitry Andric   consumeToken(); // filename
458*700637cbSDimitry Andric 
459*700637cbSDimitry Andric   return std::move(EMD);
460*700637cbSDimitry Andric }
461*700637cbSDimitry Andric 
462*700637cbSDimitry Andric /// Parse a configuration macro declaration.
463*700637cbSDimitry Andric ///
464*700637cbSDimitry Andric ///   module-declaration:
465*700637cbSDimitry Andric ///     'config_macros' attributes[opt] config-macro-list?
466*700637cbSDimitry Andric ///
467*700637cbSDimitry Andric ///   config-macro-list:
468*700637cbSDimitry Andric ///     identifier (',' identifier)?
parseConfigMacrosDecl()469*700637cbSDimitry Andric std::optional<ConfigMacrosDecl> ModuleMapFileParser::parseConfigMacrosDecl() {
470*700637cbSDimitry Andric   assert(Tok.is(MMToken::ConfigMacros));
471*700637cbSDimitry Andric   ConfigMacrosDecl CMDecl;
472*700637cbSDimitry Andric   CMDecl.Location = consumeToken();
473*700637cbSDimitry Andric 
474*700637cbSDimitry Andric   // Parse the optional attributes.
475*700637cbSDimitry Andric   ModuleAttributes Attrs;
476*700637cbSDimitry Andric   if (parseOptionalAttributes(Attrs))
477*700637cbSDimitry Andric     return std::nullopt;
478*700637cbSDimitry Andric 
479*700637cbSDimitry Andric   CMDecl.Exhaustive = Attrs.IsExhaustive;
480*700637cbSDimitry Andric 
481*700637cbSDimitry Andric   // If we don't have an identifier, we're done.
482*700637cbSDimitry Andric   // FIXME: Support macros with the same name as a keyword here.
483*700637cbSDimitry Andric   if (!Tok.is(MMToken::Identifier))
484*700637cbSDimitry Andric     return std::nullopt;
485*700637cbSDimitry Andric 
486*700637cbSDimitry Andric   // Consume the first identifier.
487*700637cbSDimitry Andric   CMDecl.Macros.push_back(Tok.getString());
488*700637cbSDimitry Andric   consumeToken();
489*700637cbSDimitry Andric 
490*700637cbSDimitry Andric   do {
491*700637cbSDimitry Andric     // If there's a comma, consume it.
492*700637cbSDimitry Andric     if (!Tok.is(MMToken::Comma))
493*700637cbSDimitry Andric       break;
494*700637cbSDimitry Andric     consumeToken();
495*700637cbSDimitry Andric 
496*700637cbSDimitry Andric     // We expect to see a macro name here.
497*700637cbSDimitry Andric     // FIXME: Support macros with the same name as a keyword here.
498*700637cbSDimitry Andric     if (!Tok.is(MMToken::Identifier)) {
499*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
500*700637cbSDimitry Andric       return std::nullopt;
501*700637cbSDimitry Andric     }
502*700637cbSDimitry Andric 
503*700637cbSDimitry Andric     // Consume the macro name.
504*700637cbSDimitry Andric     CMDecl.Macros.push_back(Tok.getString());
505*700637cbSDimitry Andric     consumeToken();
506*700637cbSDimitry Andric   } while (true);
507*700637cbSDimitry Andric   return std::move(CMDecl);
508*700637cbSDimitry Andric }
509*700637cbSDimitry Andric 
510*700637cbSDimitry Andric /// Parse a conflict declaration.
511*700637cbSDimitry Andric ///
512*700637cbSDimitry Andric ///   module-declaration:
513*700637cbSDimitry Andric ///     'conflict' module-id ',' string-literal
parseConflictDecl()514*700637cbSDimitry Andric std::optional<ConflictDecl> ModuleMapFileParser::parseConflictDecl() {
515*700637cbSDimitry Andric   assert(Tok.is(MMToken::Conflict));
516*700637cbSDimitry Andric   ConflictDecl CD;
517*700637cbSDimitry Andric   CD.Location = consumeToken();
518*700637cbSDimitry Andric 
519*700637cbSDimitry Andric   // Parse the module-id.
520*700637cbSDimitry Andric   if (parseModuleId(CD.Id))
521*700637cbSDimitry Andric     return std::nullopt;
522*700637cbSDimitry Andric 
523*700637cbSDimitry Andric   // Parse the ','.
524*700637cbSDimitry Andric   if (!Tok.is(MMToken::Comma)) {
525*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
526*700637cbSDimitry Andric         << SourceRange(CD.Location);
527*700637cbSDimitry Andric     return std::nullopt;
528*700637cbSDimitry Andric   }
529*700637cbSDimitry Andric   consumeToken();
530*700637cbSDimitry Andric 
531*700637cbSDimitry Andric   // Parse the message.
532*700637cbSDimitry Andric   if (!Tok.is(MMToken::StringLiteral)) {
533*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
534*700637cbSDimitry Andric         << formatModuleId(CD.Id);
535*700637cbSDimitry Andric     return std::nullopt;
536*700637cbSDimitry Andric   }
537*700637cbSDimitry Andric   CD.Message = Tok.getString();
538*700637cbSDimitry Andric   consumeToken();
539*700637cbSDimitry Andric   return std::move(CD);
540*700637cbSDimitry Andric }
541*700637cbSDimitry Andric 
542*700637cbSDimitry Andric /// Parse a module export declaration.
543*700637cbSDimitry Andric ///
544*700637cbSDimitry Andric ///   export-declaration:
545*700637cbSDimitry Andric ///     'export' wildcard-module-id
546*700637cbSDimitry Andric ///
547*700637cbSDimitry Andric ///   wildcard-module-id:
548*700637cbSDimitry Andric ///     identifier
549*700637cbSDimitry Andric ///     '*'
550*700637cbSDimitry Andric ///     identifier '.' wildcard-module-id
parseExportDecl()551*700637cbSDimitry Andric std::optional<ExportDecl> ModuleMapFileParser::parseExportDecl() {
552*700637cbSDimitry Andric   assert(Tok.is(MMToken::ExportKeyword));
553*700637cbSDimitry Andric   ExportDecl ED;
554*700637cbSDimitry Andric   ED.Location = consumeToken();
555*700637cbSDimitry Andric 
556*700637cbSDimitry Andric   // Parse the module-id with an optional wildcard at the end.
557*700637cbSDimitry Andric   ED.Wildcard = false;
558*700637cbSDimitry Andric   do {
559*700637cbSDimitry Andric     // FIXME: Support string-literal module names here.
560*700637cbSDimitry Andric     if (Tok.is(MMToken::Identifier)) {
561*700637cbSDimitry Andric       ED.Id.push_back(
562*700637cbSDimitry Andric           std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
563*700637cbSDimitry Andric       consumeToken();
564*700637cbSDimitry Andric 
565*700637cbSDimitry Andric       if (Tok.is(MMToken::Period)) {
566*700637cbSDimitry Andric         consumeToken();
567*700637cbSDimitry Andric         continue;
568*700637cbSDimitry Andric       }
569*700637cbSDimitry Andric 
570*700637cbSDimitry Andric       break;
571*700637cbSDimitry Andric     }
572*700637cbSDimitry Andric 
573*700637cbSDimitry Andric     if (Tok.is(MMToken::Star)) {
574*700637cbSDimitry Andric       ED.Wildcard = true;
575*700637cbSDimitry Andric       consumeToken();
576*700637cbSDimitry Andric       break;
577*700637cbSDimitry Andric     }
578*700637cbSDimitry Andric 
579*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
580*700637cbSDimitry Andric     HadError = true;
581*700637cbSDimitry Andric     return std::nullopt;
582*700637cbSDimitry Andric   } while (true);
583*700637cbSDimitry Andric 
584*700637cbSDimitry Andric   return std::move(ED);
585*700637cbSDimitry Andric }
586*700637cbSDimitry Andric 
587*700637cbSDimitry Andric /// Parse a module export_as declaration.
588*700637cbSDimitry Andric ///
589*700637cbSDimitry Andric ///   export-as-declaration:
590*700637cbSDimitry Andric ///     'export_as' identifier
parseExportAsDecl()591*700637cbSDimitry Andric std::optional<ExportAsDecl> ModuleMapFileParser::parseExportAsDecl() {
592*700637cbSDimitry Andric   assert(Tok.is(MMToken::ExportAsKeyword));
593*700637cbSDimitry Andric   ExportAsDecl EAD;
594*700637cbSDimitry Andric   EAD.Location = consumeToken();
595*700637cbSDimitry Andric 
596*700637cbSDimitry Andric   if (!Tok.is(MMToken::Identifier)) {
597*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
598*700637cbSDimitry Andric     HadError = true;
599*700637cbSDimitry Andric     return std::nullopt;
600*700637cbSDimitry Andric   }
601*700637cbSDimitry Andric 
602*700637cbSDimitry Andric   if (parseModuleId(EAD.Id))
603*700637cbSDimitry Andric     return std::nullopt;
604*700637cbSDimitry Andric   if (EAD.Id.size() > 1)
605*700637cbSDimitry Andric     Diags.Report(EAD.Id[1].second, diag::err_mmap_qualified_export_as);
606*700637cbSDimitry Andric   return std::move(EAD);
607*700637cbSDimitry Andric }
608*700637cbSDimitry Andric 
609*700637cbSDimitry Andric /// Parse a module use declaration.
610*700637cbSDimitry Andric ///
611*700637cbSDimitry Andric ///   use-declaration:
612*700637cbSDimitry Andric ///     'use' wildcard-module-id
parseUseDecl()613*700637cbSDimitry Andric std::optional<UseDecl> ModuleMapFileParser::parseUseDecl() {
614*700637cbSDimitry Andric   assert(Tok.is(MMToken::UseKeyword));
615*700637cbSDimitry Andric   UseDecl UD;
616*700637cbSDimitry Andric   UD.Location = consumeToken();
617*700637cbSDimitry Andric   if (parseModuleId(UD.Id))
618*700637cbSDimitry Andric     return std::nullopt;
619*700637cbSDimitry Andric   return std::move(UD);
620*700637cbSDimitry Andric }
621*700637cbSDimitry Andric 
622*700637cbSDimitry Andric /// Parse a requires declaration.
623*700637cbSDimitry Andric ///
624*700637cbSDimitry Andric ///   requires-declaration:
625*700637cbSDimitry Andric ///     'requires' feature-list
626*700637cbSDimitry Andric ///
627*700637cbSDimitry Andric ///   feature-list:
628*700637cbSDimitry Andric ///     feature ',' feature-list
629*700637cbSDimitry Andric ///     feature
630*700637cbSDimitry Andric ///
631*700637cbSDimitry Andric ///   feature:
632*700637cbSDimitry Andric ///     '!'[opt] identifier
parseRequiresDecl()633*700637cbSDimitry Andric std::optional<RequiresDecl> ModuleMapFileParser::parseRequiresDecl() {
634*700637cbSDimitry Andric   assert(Tok.is(MMToken::RequiresKeyword));
635*700637cbSDimitry Andric   RequiresDecl RD;
636*700637cbSDimitry Andric   RD.Location = consumeToken();
637*700637cbSDimitry Andric 
638*700637cbSDimitry Andric   // Parse the feature-list.
639*700637cbSDimitry Andric   do {
640*700637cbSDimitry Andric     bool RequiredState = true;
641*700637cbSDimitry Andric     if (Tok.is(MMToken::Exclaim)) {
642*700637cbSDimitry Andric       RequiredState = false;
643*700637cbSDimitry Andric       consumeToken();
644*700637cbSDimitry Andric     }
645*700637cbSDimitry Andric 
646*700637cbSDimitry Andric     if (!Tok.is(MMToken::Identifier)) {
647*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
648*700637cbSDimitry Andric       HadError = true;
649*700637cbSDimitry Andric       return std::nullopt;
650*700637cbSDimitry Andric     }
651*700637cbSDimitry Andric 
652*700637cbSDimitry Andric     // Consume the feature name.
653*700637cbSDimitry Andric     RequiresFeature RF;
654*700637cbSDimitry Andric     RF.Feature = Tok.getString();
655*700637cbSDimitry Andric     RF.Location = consumeToken();
656*700637cbSDimitry Andric     RF.RequiredState = RequiredState;
657*700637cbSDimitry Andric 
658*700637cbSDimitry Andric     RD.Features.push_back(std::move(RF));
659*700637cbSDimitry Andric 
660*700637cbSDimitry Andric     if (!Tok.is(MMToken::Comma))
661*700637cbSDimitry Andric       break;
662*700637cbSDimitry Andric 
663*700637cbSDimitry Andric     // Consume the comma.
664*700637cbSDimitry Andric     consumeToken();
665*700637cbSDimitry Andric   } while (true);
666*700637cbSDimitry Andric   return std::move(RD);
667*700637cbSDimitry Andric }
668*700637cbSDimitry Andric 
669*700637cbSDimitry Andric /// Parse a header declaration.
670*700637cbSDimitry Andric ///
671*700637cbSDimitry Andric ///   header-declaration:
672*700637cbSDimitry Andric ///     'textual'[opt] 'header' string-literal
673*700637cbSDimitry Andric ///     'private' 'textual'[opt] 'header' string-literal
674*700637cbSDimitry Andric ///     'exclude' 'header' string-literal
675*700637cbSDimitry Andric ///     'umbrella' 'header' string-literal
676*700637cbSDimitry Andric std::optional<HeaderDecl>
parseHeaderDecl(MMToken::TokenKind LeadingToken,clang::SourceLocation LeadingLoc)677*700637cbSDimitry Andric ModuleMapFileParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
678*700637cbSDimitry Andric                                      clang::SourceLocation LeadingLoc) {
679*700637cbSDimitry Andric   HeaderDecl HD;
680*700637cbSDimitry Andric   HD.Private = false;
681*700637cbSDimitry Andric   HD.Excluded = false;
682*700637cbSDimitry Andric   HD.Textual = false;
683*700637cbSDimitry Andric   // We've already consumed the first token.
684*700637cbSDimitry Andric   HD.Location = LeadingLoc;
685*700637cbSDimitry Andric 
686*700637cbSDimitry Andric   if (LeadingToken == MMToken::PrivateKeyword) {
687*700637cbSDimitry Andric     HD.Private = true;
688*700637cbSDimitry Andric     // 'private' may optionally be followed by 'textual'.
689*700637cbSDimitry Andric     if (Tok.is(MMToken::TextualKeyword)) {
690*700637cbSDimitry Andric       HD.Textual = true;
691*700637cbSDimitry Andric       LeadingToken = Tok.Kind;
692*700637cbSDimitry Andric       consumeToken();
693*700637cbSDimitry Andric     }
694*700637cbSDimitry Andric   } else if (LeadingToken == MMToken::ExcludeKeyword)
695*700637cbSDimitry Andric     HD.Excluded = true;
696*700637cbSDimitry Andric   else if (LeadingToken == MMToken::TextualKeyword)
697*700637cbSDimitry Andric     HD.Textual = true;
698*700637cbSDimitry Andric 
699*700637cbSDimitry Andric   if (LeadingToken != MMToken::HeaderKeyword) {
700*700637cbSDimitry Andric     if (!Tok.is(MMToken::HeaderKeyword)) {
701*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
702*700637cbSDimitry Andric           << (LeadingToken == MMToken::PrivateKeyword   ? "private"
703*700637cbSDimitry Andric               : LeadingToken == MMToken::ExcludeKeyword ? "exclude"
704*700637cbSDimitry Andric               : LeadingToken == MMToken::TextualKeyword ? "textual"
705*700637cbSDimitry Andric                                                         : "umbrella");
706*700637cbSDimitry Andric       return std::nullopt;
707*700637cbSDimitry Andric     }
708*700637cbSDimitry Andric     consumeToken();
709*700637cbSDimitry Andric   }
710*700637cbSDimitry Andric 
711*700637cbSDimitry Andric   // Parse the header name.
712*700637cbSDimitry Andric   if (!Tok.is(MMToken::StringLiteral)) {
713*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) << "header";
714*700637cbSDimitry Andric     HadError = true;
715*700637cbSDimitry Andric     return std::nullopt;
716*700637cbSDimitry Andric   }
717*700637cbSDimitry Andric   HD.Path = Tok.getString();
718*700637cbSDimitry Andric   HD.PathLoc = consumeToken();
719*700637cbSDimitry Andric   HD.Umbrella = LeadingToken == MMToken::UmbrellaKeyword;
720*700637cbSDimitry Andric 
721*700637cbSDimitry Andric   // If we were given stat information, parse it so we can skip looking for
722*700637cbSDimitry Andric   // the file.
723*700637cbSDimitry Andric   if (Tok.is(MMToken::LBrace)) {
724*700637cbSDimitry Andric     SourceLocation LBraceLoc = consumeToken();
725*700637cbSDimitry Andric 
726*700637cbSDimitry Andric     while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
727*700637cbSDimitry Andric       enum Attribute { Size, ModTime, Unknown };
728*700637cbSDimitry Andric       StringRef Str = Tok.getString();
729*700637cbSDimitry Andric       SourceLocation Loc = consumeToken();
730*700637cbSDimitry Andric       switch (llvm::StringSwitch<Attribute>(Str)
731*700637cbSDimitry Andric                   .Case("size", Size)
732*700637cbSDimitry Andric                   .Case("mtime", ModTime)
733*700637cbSDimitry Andric                   .Default(Unknown)) {
734*700637cbSDimitry Andric       case Size:
735*700637cbSDimitry Andric         if (HD.Size)
736*700637cbSDimitry Andric           Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
737*700637cbSDimitry Andric         if (!Tok.is(MMToken::IntegerLiteral)) {
738*700637cbSDimitry Andric           Diags.Report(Tok.getLocation(),
739*700637cbSDimitry Andric                        diag::err_mmap_invalid_header_attribute_value)
740*700637cbSDimitry Andric               << Str;
741*700637cbSDimitry Andric           skipUntil(MMToken::RBrace);
742*700637cbSDimitry Andric           break;
743*700637cbSDimitry Andric         }
744*700637cbSDimitry Andric         HD.Size = Tok.getInteger();
745*700637cbSDimitry Andric         consumeToken();
746*700637cbSDimitry Andric         break;
747*700637cbSDimitry Andric 
748*700637cbSDimitry Andric       case ModTime:
749*700637cbSDimitry Andric         if (HD.MTime)
750*700637cbSDimitry Andric           Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
751*700637cbSDimitry Andric         if (!Tok.is(MMToken::IntegerLiteral)) {
752*700637cbSDimitry Andric           Diags.Report(Tok.getLocation(),
753*700637cbSDimitry Andric                        diag::err_mmap_invalid_header_attribute_value)
754*700637cbSDimitry Andric               << Str;
755*700637cbSDimitry Andric           skipUntil(MMToken::RBrace);
756*700637cbSDimitry Andric           break;
757*700637cbSDimitry Andric         }
758*700637cbSDimitry Andric         HD.MTime = Tok.getInteger();
759*700637cbSDimitry Andric         consumeToken();
760*700637cbSDimitry Andric         break;
761*700637cbSDimitry Andric 
762*700637cbSDimitry Andric       case Unknown:
763*700637cbSDimitry Andric         Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
764*700637cbSDimitry Andric         skipUntil(MMToken::RBrace);
765*700637cbSDimitry Andric         break;
766*700637cbSDimitry Andric       }
767*700637cbSDimitry Andric     }
768*700637cbSDimitry Andric 
769*700637cbSDimitry Andric     if (Tok.is(MMToken::RBrace))
770*700637cbSDimitry Andric       consumeToken();
771*700637cbSDimitry Andric     else {
772*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
773*700637cbSDimitry Andric       Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
774*700637cbSDimitry Andric       HadError = true;
775*700637cbSDimitry Andric     }
776*700637cbSDimitry Andric   }
777*700637cbSDimitry Andric   return std::move(HD);
778*700637cbSDimitry Andric }
779*700637cbSDimitry Andric 
780*700637cbSDimitry Andric /// Parse an exclude declaration.
781*700637cbSDimitry Andric ///
782*700637cbSDimitry Andric /// exclude-declaration:
783*700637cbSDimitry Andric ///   'exclude' identifier
784*700637cbSDimitry Andric std::optional<ExcludeDecl>
parseExcludeDecl(clang::SourceLocation LeadingLoc)785*700637cbSDimitry Andric ModuleMapFileParser::parseExcludeDecl(clang::SourceLocation LeadingLoc) {
786*700637cbSDimitry Andric   // FIXME: Support string-literal module names here.
787*700637cbSDimitry Andric   if (!Tok.is(MMToken::Identifier)) {
788*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
789*700637cbSDimitry Andric     HadError = true;
790*700637cbSDimitry Andric     return std::nullopt;
791*700637cbSDimitry Andric   }
792*700637cbSDimitry Andric 
793*700637cbSDimitry Andric   ExcludeDecl ED;
794*700637cbSDimitry Andric   ED.Location = LeadingLoc;
795*700637cbSDimitry Andric   ED.Module = Tok.getString();
796*700637cbSDimitry Andric   consumeToken();
797*700637cbSDimitry Andric   return std::move(ED);
798*700637cbSDimitry Andric }
799*700637cbSDimitry Andric 
800*700637cbSDimitry Andric /// Parse an umbrella directory declaration.
801*700637cbSDimitry Andric ///
802*700637cbSDimitry Andric ///   umbrella-dir-declaration:
803*700637cbSDimitry Andric ///     umbrella string-literal
804*700637cbSDimitry Andric std::optional<UmbrellaDirDecl>
parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc)805*700637cbSDimitry Andric ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) {
806*700637cbSDimitry Andric   UmbrellaDirDecl UDD;
807*700637cbSDimitry Andric   UDD.Location = UmbrellaLoc;
808*700637cbSDimitry Andric   // Parse the directory name.
809*700637cbSDimitry Andric   if (!Tok.is(MMToken::StringLiteral)) {
810*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
811*700637cbSDimitry Andric         << "umbrella";
812*700637cbSDimitry Andric     HadError = true;
813*700637cbSDimitry Andric     return std::nullopt;
814*700637cbSDimitry Andric   }
815*700637cbSDimitry Andric 
816*700637cbSDimitry Andric   UDD.Path = Tok.getString();
817*700637cbSDimitry Andric   consumeToken();
818*700637cbSDimitry Andric   return std::move(UDD);
819*700637cbSDimitry Andric }
820*700637cbSDimitry Andric 
821*700637cbSDimitry Andric /// Parse a link declaration.
822*700637cbSDimitry Andric ///
823*700637cbSDimitry Andric ///   module-declaration:
824*700637cbSDimitry Andric ///     'link' 'framework'[opt] string-literal
parseLinkDecl()825*700637cbSDimitry Andric std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() {
826*700637cbSDimitry Andric   assert(Tok.is(MMToken::LinkKeyword));
827*700637cbSDimitry Andric   LinkDecl LD;
828*700637cbSDimitry Andric   LD.Location = consumeToken();
829*700637cbSDimitry Andric 
830*700637cbSDimitry Andric   // Parse the optional 'framework' keyword.
831*700637cbSDimitry Andric   LD.Framework = false;
832*700637cbSDimitry Andric   if (Tok.is(MMToken::FrameworkKeyword)) {
833*700637cbSDimitry Andric     consumeToken();
834*700637cbSDimitry Andric     LD.Framework = true;
835*700637cbSDimitry Andric   }
836*700637cbSDimitry Andric 
837*700637cbSDimitry Andric   // Parse the library name
838*700637cbSDimitry Andric   if (!Tok.is(MMToken::StringLiteral)) {
839*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
840*700637cbSDimitry Andric         << LD.Framework << SourceRange(LD.Location);
841*700637cbSDimitry Andric     HadError = true;
842*700637cbSDimitry Andric     return std::nullopt;
843*700637cbSDimitry Andric   }
844*700637cbSDimitry Andric 
845*700637cbSDimitry Andric   LD.Library = Tok.getString();
846*700637cbSDimitry Andric   consumeToken();
847*700637cbSDimitry Andric   return std::move(LD);
848*700637cbSDimitry Andric }
849*700637cbSDimitry Andric 
consumeToken()850*700637cbSDimitry Andric SourceLocation ModuleMapFileParser::consumeToken() {
851*700637cbSDimitry Andric   SourceLocation Result = Tok.getLocation();
852*700637cbSDimitry Andric 
853*700637cbSDimitry Andric retry:
854*700637cbSDimitry Andric   Tok.clear();
855*700637cbSDimitry Andric   Token LToken;
856*700637cbSDimitry Andric   L.LexFromRawLexer(LToken);
857*700637cbSDimitry Andric   Tok.Location = LToken.getLocation().getRawEncoding();
858*700637cbSDimitry Andric   switch (LToken.getKind()) {
859*700637cbSDimitry Andric   case tok::raw_identifier: {
860*700637cbSDimitry Andric     StringRef RI = LToken.getRawIdentifier();
861*700637cbSDimitry Andric     Tok.StringData = RI.data();
862*700637cbSDimitry Andric     Tok.StringLength = RI.size();
863*700637cbSDimitry Andric     Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
864*700637cbSDimitry Andric                    .Case("config_macros", MMToken::ConfigMacros)
865*700637cbSDimitry Andric                    .Case("conflict", MMToken::Conflict)
866*700637cbSDimitry Andric                    .Case("exclude", MMToken::ExcludeKeyword)
867*700637cbSDimitry Andric                    .Case("explicit", MMToken::ExplicitKeyword)
868*700637cbSDimitry Andric                    .Case("export", MMToken::ExportKeyword)
869*700637cbSDimitry Andric                    .Case("export_as", MMToken::ExportAsKeyword)
870*700637cbSDimitry Andric                    .Case("extern", MMToken::ExternKeyword)
871*700637cbSDimitry Andric                    .Case("framework", MMToken::FrameworkKeyword)
872*700637cbSDimitry Andric                    .Case("header", MMToken::HeaderKeyword)
873*700637cbSDimitry Andric                    .Case("link", MMToken::LinkKeyword)
874*700637cbSDimitry Andric                    .Case("module", MMToken::ModuleKeyword)
875*700637cbSDimitry Andric                    .Case("private", MMToken::PrivateKeyword)
876*700637cbSDimitry Andric                    .Case("requires", MMToken::RequiresKeyword)
877*700637cbSDimitry Andric                    .Case("textual", MMToken::TextualKeyword)
878*700637cbSDimitry Andric                    .Case("umbrella", MMToken::UmbrellaKeyword)
879*700637cbSDimitry Andric                    .Case("use", MMToken::UseKeyword)
880*700637cbSDimitry Andric                    .Default(MMToken::Identifier);
881*700637cbSDimitry Andric     break;
882*700637cbSDimitry Andric   }
883*700637cbSDimitry Andric 
884*700637cbSDimitry Andric   case tok::comma:
885*700637cbSDimitry Andric     Tok.Kind = MMToken::Comma;
886*700637cbSDimitry Andric     break;
887*700637cbSDimitry Andric 
888*700637cbSDimitry Andric   case tok::eof:
889*700637cbSDimitry Andric     Tok.Kind = MMToken::EndOfFile;
890*700637cbSDimitry Andric     break;
891*700637cbSDimitry Andric 
892*700637cbSDimitry Andric   case tok::l_brace:
893*700637cbSDimitry Andric     Tok.Kind = MMToken::LBrace;
894*700637cbSDimitry Andric     break;
895*700637cbSDimitry Andric 
896*700637cbSDimitry Andric   case tok::l_square:
897*700637cbSDimitry Andric     Tok.Kind = MMToken::LSquare;
898*700637cbSDimitry Andric     break;
899*700637cbSDimitry Andric 
900*700637cbSDimitry Andric   case tok::period:
901*700637cbSDimitry Andric     Tok.Kind = MMToken::Period;
902*700637cbSDimitry Andric     break;
903*700637cbSDimitry Andric 
904*700637cbSDimitry Andric   case tok::r_brace:
905*700637cbSDimitry Andric     Tok.Kind = MMToken::RBrace;
906*700637cbSDimitry Andric     break;
907*700637cbSDimitry Andric 
908*700637cbSDimitry Andric   case tok::r_square:
909*700637cbSDimitry Andric     Tok.Kind = MMToken::RSquare;
910*700637cbSDimitry Andric     break;
911*700637cbSDimitry Andric 
912*700637cbSDimitry Andric   case tok::star:
913*700637cbSDimitry Andric     Tok.Kind = MMToken::Star;
914*700637cbSDimitry Andric     break;
915*700637cbSDimitry Andric 
916*700637cbSDimitry Andric   case tok::exclaim:
917*700637cbSDimitry Andric     Tok.Kind = MMToken::Exclaim;
918*700637cbSDimitry Andric     break;
919*700637cbSDimitry Andric 
920*700637cbSDimitry Andric   case tok::string_literal: {
921*700637cbSDimitry Andric     if (LToken.hasUDSuffix()) {
922*700637cbSDimitry Andric       Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
923*700637cbSDimitry Andric       HadError = true;
924*700637cbSDimitry Andric       goto retry;
925*700637cbSDimitry Andric     }
926*700637cbSDimitry Andric 
927*700637cbSDimitry Andric     // Form the token.
928*700637cbSDimitry Andric     Tok.Kind = MMToken::StringLiteral;
929*700637cbSDimitry Andric     Tok.StringData = LToken.getLiteralData() + 1;
930*700637cbSDimitry Andric     Tok.StringLength = LToken.getLength() - 2;
931*700637cbSDimitry Andric     break;
932*700637cbSDimitry Andric   }
933*700637cbSDimitry Andric 
934*700637cbSDimitry Andric   case tok::numeric_constant: {
935*700637cbSDimitry Andric     // We don't support any suffixes or other complications.
936*700637cbSDimitry Andric     uint64_t Value;
937*700637cbSDimitry Andric     if (StringRef(LToken.getLiteralData(), LToken.getLength())
938*700637cbSDimitry Andric             .getAsInteger(0, Value)) {
939*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
940*700637cbSDimitry Andric       HadError = true;
941*700637cbSDimitry Andric       goto retry;
942*700637cbSDimitry Andric     }
943*700637cbSDimitry Andric 
944*700637cbSDimitry Andric     Tok.Kind = MMToken::IntegerLiteral;
945*700637cbSDimitry Andric     Tok.IntegerValue = Value;
946*700637cbSDimitry Andric     break;
947*700637cbSDimitry Andric   }
948*700637cbSDimitry Andric 
949*700637cbSDimitry Andric   case tok::comment:
950*700637cbSDimitry Andric     goto retry;
951*700637cbSDimitry Andric 
952*700637cbSDimitry Andric   case tok::hash:
953*700637cbSDimitry Andric     // A module map can be terminated prematurely by
954*700637cbSDimitry Andric     //   #pragma clang module contents
955*700637cbSDimitry Andric     // When building the module, we'll treat the rest of the file as the
956*700637cbSDimitry Andric     // contents of the module.
957*700637cbSDimitry Andric     {
958*700637cbSDimitry Andric       auto NextIsIdent = [&](StringRef Str) -> bool {
959*700637cbSDimitry Andric         L.LexFromRawLexer(LToken);
960*700637cbSDimitry Andric         return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
961*700637cbSDimitry Andric                LToken.getRawIdentifier() == Str;
962*700637cbSDimitry Andric       };
963*700637cbSDimitry Andric       if (NextIsIdent("pragma") && NextIsIdent("clang") &&
964*700637cbSDimitry Andric           NextIsIdent("module") && NextIsIdent("contents")) {
965*700637cbSDimitry Andric         Tok.Kind = MMToken::EndOfFile;
966*700637cbSDimitry Andric         break;
967*700637cbSDimitry Andric       }
968*700637cbSDimitry Andric     }
969*700637cbSDimitry Andric     [[fallthrough]];
970*700637cbSDimitry Andric 
971*700637cbSDimitry Andric   default:
972*700637cbSDimitry Andric     Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
973*700637cbSDimitry Andric     HadError = true;
974*700637cbSDimitry Andric     goto retry;
975*700637cbSDimitry Andric   }
976*700637cbSDimitry Andric 
977*700637cbSDimitry Andric   return Result;
978*700637cbSDimitry Andric }
979*700637cbSDimitry Andric 
skipUntil(MMToken::TokenKind K)980*700637cbSDimitry Andric void ModuleMapFileParser::skipUntil(MMToken::TokenKind K) {
981*700637cbSDimitry Andric   unsigned braceDepth = 0;
982*700637cbSDimitry Andric   unsigned squareDepth = 0;
983*700637cbSDimitry Andric   do {
984*700637cbSDimitry Andric     switch (Tok.Kind) {
985*700637cbSDimitry Andric     case MMToken::EndOfFile:
986*700637cbSDimitry Andric       return;
987*700637cbSDimitry Andric 
988*700637cbSDimitry Andric     case MMToken::LBrace:
989*700637cbSDimitry Andric       if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
990*700637cbSDimitry Andric         return;
991*700637cbSDimitry Andric 
992*700637cbSDimitry Andric       ++braceDepth;
993*700637cbSDimitry Andric       break;
994*700637cbSDimitry Andric 
995*700637cbSDimitry Andric     case MMToken::LSquare:
996*700637cbSDimitry Andric       if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
997*700637cbSDimitry Andric         return;
998*700637cbSDimitry Andric 
999*700637cbSDimitry Andric       ++squareDepth;
1000*700637cbSDimitry Andric       break;
1001*700637cbSDimitry Andric 
1002*700637cbSDimitry Andric     case MMToken::RBrace:
1003*700637cbSDimitry Andric       if (braceDepth > 0)
1004*700637cbSDimitry Andric         --braceDepth;
1005*700637cbSDimitry Andric       else if (Tok.is(K))
1006*700637cbSDimitry Andric         return;
1007*700637cbSDimitry Andric       break;
1008*700637cbSDimitry Andric 
1009*700637cbSDimitry Andric     case MMToken::RSquare:
1010*700637cbSDimitry Andric       if (squareDepth > 0)
1011*700637cbSDimitry Andric         --squareDepth;
1012*700637cbSDimitry Andric       else if (Tok.is(K))
1013*700637cbSDimitry Andric         return;
1014*700637cbSDimitry Andric       break;
1015*700637cbSDimitry Andric 
1016*700637cbSDimitry Andric     default:
1017*700637cbSDimitry Andric       if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
1018*700637cbSDimitry Andric         return;
1019*700637cbSDimitry Andric       break;
1020*700637cbSDimitry Andric     }
1021*700637cbSDimitry Andric 
1022*700637cbSDimitry Andric     consumeToken();
1023*700637cbSDimitry Andric   } while (true);
1024*700637cbSDimitry Andric }
1025*700637cbSDimitry Andric 
1026*700637cbSDimitry Andric /// Parse a module-id.
1027*700637cbSDimitry Andric ///
1028*700637cbSDimitry Andric ///   module-id:
1029*700637cbSDimitry Andric ///     identifier
1030*700637cbSDimitry Andric ///     identifier '.' module-id
1031*700637cbSDimitry Andric ///
1032*700637cbSDimitry Andric /// \returns true if an error occurred, false otherwise.
parseModuleId(ModuleId & Id)1033*700637cbSDimitry Andric bool ModuleMapFileParser::parseModuleId(ModuleId &Id) {
1034*700637cbSDimitry Andric   Id.clear();
1035*700637cbSDimitry Andric   do {
1036*700637cbSDimitry Andric     if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
1037*700637cbSDimitry Andric       Id.push_back(
1038*700637cbSDimitry Andric           std::make_pair(std::string(Tok.getString()), Tok.getLocation()));
1039*700637cbSDimitry Andric       consumeToken();
1040*700637cbSDimitry Andric     } else {
1041*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
1042*700637cbSDimitry Andric       return true;
1043*700637cbSDimitry Andric     }
1044*700637cbSDimitry Andric 
1045*700637cbSDimitry Andric     if (!Tok.is(MMToken::Period))
1046*700637cbSDimitry Andric       break;
1047*700637cbSDimitry Andric 
1048*700637cbSDimitry Andric     consumeToken();
1049*700637cbSDimitry Andric   } while (true);
1050*700637cbSDimitry Andric 
1051*700637cbSDimitry Andric   return false;
1052*700637cbSDimitry Andric }
1053*700637cbSDimitry Andric 
1054*700637cbSDimitry Andric /// Parse optional attributes.
1055*700637cbSDimitry Andric ///
1056*700637cbSDimitry Andric ///   attributes:
1057*700637cbSDimitry Andric ///     attribute attributes
1058*700637cbSDimitry Andric ///     attribute
1059*700637cbSDimitry Andric ///
1060*700637cbSDimitry Andric ///   attribute:
1061*700637cbSDimitry Andric ///     [ identifier ]
1062*700637cbSDimitry Andric ///
1063*700637cbSDimitry Andric /// \param Attrs Will be filled in with the parsed attributes.
1064*700637cbSDimitry Andric ///
1065*700637cbSDimitry Andric /// \returns true if an error occurred, false otherwise.
parseOptionalAttributes(ModuleAttributes & Attrs)1066*700637cbSDimitry Andric bool ModuleMapFileParser::parseOptionalAttributes(ModuleAttributes &Attrs) {
1067*700637cbSDimitry Andric   bool Error = false;
1068*700637cbSDimitry Andric 
1069*700637cbSDimitry Andric   while (Tok.is(MMToken::LSquare)) {
1070*700637cbSDimitry Andric     // Consume the '['.
1071*700637cbSDimitry Andric     SourceLocation LSquareLoc = consumeToken();
1072*700637cbSDimitry Andric 
1073*700637cbSDimitry Andric     // Check whether we have an attribute name here.
1074*700637cbSDimitry Andric     if (!Tok.is(MMToken::Identifier)) {
1075*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
1076*700637cbSDimitry Andric       skipUntil(MMToken::RSquare);
1077*700637cbSDimitry Andric       if (Tok.is(MMToken::RSquare))
1078*700637cbSDimitry Andric         consumeToken();
1079*700637cbSDimitry Andric       Error = true;
1080*700637cbSDimitry Andric     }
1081*700637cbSDimitry Andric 
1082*700637cbSDimitry Andric     /// Enumerates the known attributes.
1083*700637cbSDimitry Andric     enum AttributeKind {
1084*700637cbSDimitry Andric       /// An unknown attribute.
1085*700637cbSDimitry Andric       AT_unknown,
1086*700637cbSDimitry Andric 
1087*700637cbSDimitry Andric       /// The 'system' attribute.
1088*700637cbSDimitry Andric       AT_system,
1089*700637cbSDimitry Andric 
1090*700637cbSDimitry Andric       /// The 'extern_c' attribute.
1091*700637cbSDimitry Andric       AT_extern_c,
1092*700637cbSDimitry Andric 
1093*700637cbSDimitry Andric       /// The 'exhaustive' attribute.
1094*700637cbSDimitry Andric       AT_exhaustive,
1095*700637cbSDimitry Andric 
1096*700637cbSDimitry Andric       /// The 'no_undeclared_includes' attribute.
1097*700637cbSDimitry Andric       AT_no_undeclared_includes
1098*700637cbSDimitry Andric     };
1099*700637cbSDimitry Andric 
1100*700637cbSDimitry Andric     // Decode the attribute name.
1101*700637cbSDimitry Andric     AttributeKind Attribute =
1102*700637cbSDimitry Andric         llvm::StringSwitch<AttributeKind>(Tok.getString())
1103*700637cbSDimitry Andric             .Case("exhaustive", AT_exhaustive)
1104*700637cbSDimitry Andric             .Case("extern_c", AT_extern_c)
1105*700637cbSDimitry Andric             .Case("no_undeclared_includes", AT_no_undeclared_includes)
1106*700637cbSDimitry Andric             .Case("system", AT_system)
1107*700637cbSDimitry Andric             .Default(AT_unknown);
1108*700637cbSDimitry Andric     switch (Attribute) {
1109*700637cbSDimitry Andric     case AT_unknown:
1110*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
1111*700637cbSDimitry Andric           << Tok.getString();
1112*700637cbSDimitry Andric       break;
1113*700637cbSDimitry Andric 
1114*700637cbSDimitry Andric     case AT_system:
1115*700637cbSDimitry Andric       Attrs.IsSystem = true;
1116*700637cbSDimitry Andric       break;
1117*700637cbSDimitry Andric 
1118*700637cbSDimitry Andric     case AT_extern_c:
1119*700637cbSDimitry Andric       Attrs.IsExternC = true;
1120*700637cbSDimitry Andric       break;
1121*700637cbSDimitry Andric 
1122*700637cbSDimitry Andric     case AT_exhaustive:
1123*700637cbSDimitry Andric       Attrs.IsExhaustive = true;
1124*700637cbSDimitry Andric       break;
1125*700637cbSDimitry Andric 
1126*700637cbSDimitry Andric     case AT_no_undeclared_includes:
1127*700637cbSDimitry Andric       Attrs.NoUndeclaredIncludes = true;
1128*700637cbSDimitry Andric       break;
1129*700637cbSDimitry Andric     }
1130*700637cbSDimitry Andric     consumeToken();
1131*700637cbSDimitry Andric 
1132*700637cbSDimitry Andric     // Consume the ']'.
1133*700637cbSDimitry Andric     if (!Tok.is(MMToken::RSquare)) {
1134*700637cbSDimitry Andric       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
1135*700637cbSDimitry Andric       Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
1136*700637cbSDimitry Andric       skipUntil(MMToken::RSquare);
1137*700637cbSDimitry Andric       Error = true;
1138*700637cbSDimitry Andric     }
1139*700637cbSDimitry Andric 
1140*700637cbSDimitry Andric     if (Tok.is(MMToken::RSquare))
1141*700637cbSDimitry Andric       consumeToken();
1142*700637cbSDimitry Andric   }
1143*700637cbSDimitry Andric 
1144*700637cbSDimitry Andric   if (Error)
1145*700637cbSDimitry Andric     HadError = true;
1146*700637cbSDimitry Andric 
1147*700637cbSDimitry Andric   return Error;
1148*700637cbSDimitry Andric }
1149*700637cbSDimitry Andric 
1150*700637cbSDimitry Andric static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out, int depth);
1151*700637cbSDimitry Andric 
dumpExternModule(const ExternModuleDecl & EMD,llvm::raw_ostream & out,int depth)1152*700637cbSDimitry Andric static void dumpExternModule(const ExternModuleDecl &EMD,
1153*700637cbSDimitry Andric                              llvm::raw_ostream &out, int depth) {
1154*700637cbSDimitry Andric   out.indent(depth * 2);
1155*700637cbSDimitry Andric   out << "extern module " << formatModuleId(EMD.Id) << " \"" << EMD.Path
1156*700637cbSDimitry Andric       << "\"\n";
1157*700637cbSDimitry Andric }
1158*700637cbSDimitry Andric 
dumpDecls(ArrayRef<Decl> Decls,llvm::raw_ostream & out,int depth)1159*700637cbSDimitry Andric static void dumpDecls(ArrayRef<Decl> Decls, llvm::raw_ostream &out, int depth) {
1160*700637cbSDimitry Andric   for (const auto &Decl : Decls) {
1161*700637cbSDimitry Andric     std::visit(llvm::makeVisitor(
1162*700637cbSDimitry Andric                    [&](const RequiresDecl &RD) {
1163*700637cbSDimitry Andric                      out.indent(depth * 2);
1164*700637cbSDimitry Andric                      out << "requires\n";
1165*700637cbSDimitry Andric                    },
1166*700637cbSDimitry Andric                    [&](const HeaderDecl &HD) {
1167*700637cbSDimitry Andric                      out.indent(depth * 2);
1168*700637cbSDimitry Andric                      if (HD.Private)
1169*700637cbSDimitry Andric                        out << "private ";
1170*700637cbSDimitry Andric                      if (HD.Textual)
1171*700637cbSDimitry Andric                        out << "textual ";
1172*700637cbSDimitry Andric                      if (HD.Excluded)
1173*700637cbSDimitry Andric                        out << "excluded ";
1174*700637cbSDimitry Andric                      if (HD.Umbrella)
1175*700637cbSDimitry Andric                        out << "umbrella ";
1176*700637cbSDimitry Andric                      out << "header \"" << HD.Path << "\"\n";
1177*700637cbSDimitry Andric                    },
1178*700637cbSDimitry Andric                    [&](const UmbrellaDirDecl &UDD) {
1179*700637cbSDimitry Andric                      out.indent(depth * 2);
1180*700637cbSDimitry Andric                      out << "umbrella\n";
1181*700637cbSDimitry Andric                    },
1182*700637cbSDimitry Andric                    [&](const ModuleDecl &MD) { dumpModule(MD, out, depth); },
1183*700637cbSDimitry Andric                    [&](const ExcludeDecl &ED) {
1184*700637cbSDimitry Andric                      out.indent(depth * 2);
1185*700637cbSDimitry Andric                      out << "exclude " << ED.Module << "\n";
1186*700637cbSDimitry Andric                    },
1187*700637cbSDimitry Andric                    [&](const ExportDecl &ED) {
1188*700637cbSDimitry Andric                      out.indent(depth * 2);
1189*700637cbSDimitry Andric                      out << "export "
1190*700637cbSDimitry Andric                          << (ED.Wildcard ? "*" : formatModuleId(ED.Id)) << "\n";
1191*700637cbSDimitry Andric                    },
1192*700637cbSDimitry Andric                    [&](const ExportAsDecl &EAD) {
1193*700637cbSDimitry Andric                      out.indent(depth * 2);
1194*700637cbSDimitry Andric                      out << "export as\n";
1195*700637cbSDimitry Andric                    },
1196*700637cbSDimitry Andric                    [&](const ExternModuleDecl &EMD) {
1197*700637cbSDimitry Andric                      dumpExternModule(EMD, out, depth);
1198*700637cbSDimitry Andric                    },
1199*700637cbSDimitry Andric                    [&](const UseDecl &UD) {
1200*700637cbSDimitry Andric                      out.indent(depth * 2);
1201*700637cbSDimitry Andric                      out << "use\n";
1202*700637cbSDimitry Andric                    },
1203*700637cbSDimitry Andric                    [&](const LinkDecl &LD) {
1204*700637cbSDimitry Andric                      out.indent(depth * 2);
1205*700637cbSDimitry Andric                      out << "link\n";
1206*700637cbSDimitry Andric                    },
1207*700637cbSDimitry Andric                    [&](const ConfigMacrosDecl &CMD) {
1208*700637cbSDimitry Andric                      out.indent(depth * 2);
1209*700637cbSDimitry Andric                      out << "config_macros ";
1210*700637cbSDimitry Andric                      if (CMD.Exhaustive)
1211*700637cbSDimitry Andric                        out << "[exhaustive] ";
1212*700637cbSDimitry Andric                      for (auto Macro : CMD.Macros) {
1213*700637cbSDimitry Andric                        out << Macro << " ";
1214*700637cbSDimitry Andric                      }
1215*700637cbSDimitry Andric                      out << "\n";
1216*700637cbSDimitry Andric                    },
1217*700637cbSDimitry Andric                    [&](const ConflictDecl &CD) {
1218*700637cbSDimitry Andric                      out.indent(depth * 2);
1219*700637cbSDimitry Andric                      out << "conflicts\n";
1220*700637cbSDimitry Andric                    }),
1221*700637cbSDimitry Andric                Decl);
1222*700637cbSDimitry Andric   }
1223*700637cbSDimitry Andric }
1224*700637cbSDimitry Andric 
dumpModule(const ModuleDecl & MD,llvm::raw_ostream & out,int depth)1225*700637cbSDimitry Andric static void dumpModule(const ModuleDecl &MD, llvm::raw_ostream &out,
1226*700637cbSDimitry Andric                        int depth) {
1227*700637cbSDimitry Andric   out.indent(depth * 2);
1228*700637cbSDimitry Andric   out << "module " << formatModuleId(MD.Id) << "\n";
1229*700637cbSDimitry Andric   dumpDecls(MD.Decls, out, depth + 1);
1230*700637cbSDimitry Andric }
1231*700637cbSDimitry Andric 
dump(llvm::raw_ostream & out) const1232*700637cbSDimitry Andric void ModuleMapFile::dump(llvm::raw_ostream &out) const {
1233*700637cbSDimitry Andric   for (const auto &Decl : Decls) {
1234*700637cbSDimitry Andric     std::visit(
1235*700637cbSDimitry Andric         llvm::makeVisitor([&](const ModuleDecl &MD) { dumpModule(MD, out, 0); },
1236*700637cbSDimitry Andric                           [&](const ExternModuleDecl &EMD) {
1237*700637cbSDimitry Andric                             dumpExternModule(EMD, out, 0);
1238*700637cbSDimitry Andric                           }),
1239*700637cbSDimitry Andric         Decl);
1240*700637cbSDimitry Andric   }
1241*700637cbSDimitry Andric }
1242