Skip to content

Commit 8fb88f5

Browse files
authored
[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.
1 parent 39bab1d commit 8fb88f5

File tree

10 files changed

+1685
-1296
lines changed

10 files changed

+1685
-1296
lines changed

clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,8 @@ def warn_mmap_redundant_export_as : Warning<
917917
InGroup<PrivateModule>;
918918
def err_mmap_submodule_export_as : Error<
919919
"only top-level modules can be re-exported as public">;
920+
def err_mmap_qualified_export_as : Error<
921+
"a module can only be re-exported as another top-level module">;
920922

921923
def warn_quoted_include_in_framework_header : Warning<
922924
"double-quoted include \"%0\" in framework header, "

clang/include/clang/Basic/Module.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,30 @@ struct ASTFileSignature : std::array<uint8_t, 20> {
100100
}
101101
};
102102

103+
/// The set of attributes that can be attached to a module.
104+
struct ModuleAttributes {
105+
/// Whether this is a system module.
106+
LLVM_PREFERRED_TYPE(bool)
107+
unsigned IsSystem : 1;
108+
109+
/// Whether this is an extern "C" module.
110+
LLVM_PREFERRED_TYPE(bool)
111+
unsigned IsExternC : 1;
112+
113+
/// Whether this is an exhaustive set of configuration macros.
114+
LLVM_PREFERRED_TYPE(bool)
115+
unsigned IsExhaustive : 1;
116+
117+
/// Whether files in this module can only include non-modular headers
118+
/// and headers from used modules.
119+
LLVM_PREFERRED_TYPE(bool)
120+
unsigned NoUndeclaredIncludes : 1;
121+
122+
ModuleAttributes()
123+
: IsSystem(false), IsExternC(false), IsExhaustive(false),
124+
NoUndeclaredIncludes(false) {}
125+
};
126+
103127
/// Required to construct a Module.
104128
///
105129
/// This tag type is only constructible by ModuleMap, guaranteeing it ownership

clang/include/clang/Lex/ModuleMap.h

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -232,29 +232,7 @@ class ModuleMap {
232232

233233
llvm::DenseMap<Module *, unsigned> ModuleScopeIDs;
234234

235-
/// The set of attributes that can be attached to a module.
236-
struct Attributes {
237-
/// Whether this is a system module.
238-
LLVM_PREFERRED_TYPE(bool)
239-
unsigned IsSystem : 1;
240-
241-
/// Whether this is an extern "C" module.
242-
LLVM_PREFERRED_TYPE(bool)
243-
unsigned IsExternC : 1;
244-
245-
/// Whether this is an exhaustive set of configuration macros.
246-
LLVM_PREFERRED_TYPE(bool)
247-
unsigned IsExhaustive : 1;
248-
249-
/// Whether files in this module can only include non-modular headers
250-
/// and headers from used modules.
251-
LLVM_PREFERRED_TYPE(bool)
252-
unsigned NoUndeclaredIncludes : 1;
253-
254-
Attributes()
255-
: IsSystem(false), IsExternC(false), IsExhaustive(false),
256-
NoUndeclaredIncludes(false) {}
257-
};
235+
using Attributes = ModuleAttributes;
258236

259237
/// A directory for which framework modules can be inferred.
260238
struct InferredDirectory {
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//===- ModuleMapFile.h - Parsing and representation -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LEX_MODULEMAPFILE_H
10+
#define LLVM_CLANG_LEX_MODULEMAPFILE_H
11+
12+
#include "clang/Basic/LLVM.h"
13+
// TODO: Consider moving ModuleId to another header, parsing a modulemap file is
14+
// intended to not depend on anything about the clang::Module class.
15+
#include "clang/Basic/Module.h"
16+
#include "clang/Basic/SourceLocation.h"
17+
#include "llvm/ADT/StringRef.h"
18+
19+
#include <optional>
20+
#include <variant>
21+
22+
namespace clang {
23+
24+
class DiagnosticsEngine;
25+
class SourceManager;
26+
27+
namespace modulemap {
28+
29+
struct ExportDecl;
30+
31+
/// All declarations that can appear in a `module` declaration.
32+
using Decl =
33+
std::variant<struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl,
34+
struct ModuleDecl, struct ExcludeDecl, struct ExportDecl,
35+
struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl,
36+
struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl>;
37+
38+
struct RequiresFeature {
39+
StringRef Feature;
40+
SourceLocation Location;
41+
bool RequiredState = true; /// False if preceded by '!'.
42+
};
43+
44+
struct RequiresDecl {
45+
SourceLocation Location;
46+
std::vector<RequiresFeature> Features;
47+
};
48+
49+
struct HeaderDecl {
50+
StringRef Path;
51+
SourceLocation Location;
52+
SourceLocation PathLoc;
53+
std::optional<int64_t> Size;
54+
std::optional<int64_t> MTime;
55+
LLVM_PREFERRED_TYPE(bool)
56+
unsigned Private : 1;
57+
LLVM_PREFERRED_TYPE(bool)
58+
unsigned Textual : 1;
59+
LLVM_PREFERRED_TYPE(bool)
60+
unsigned Umbrella : 1;
61+
LLVM_PREFERRED_TYPE(bool)
62+
unsigned Excluded : 1;
63+
};
64+
65+
struct UmbrellaDirDecl {
66+
StringRef Path;
67+
SourceLocation Location;
68+
};
69+
70+
struct ModuleDecl {
71+
ModuleId Id;
72+
SourceLocation Location; /// Points to the first keyword in the decl.
73+
ModuleAttributes Attrs;
74+
std::vector<Decl> Decls;
75+
76+
LLVM_PREFERRED_TYPE(bool)
77+
unsigned Explicit : 1;
78+
LLVM_PREFERRED_TYPE(bool)
79+
unsigned Framework : 1;
80+
};
81+
82+
struct ExcludeDecl {
83+
SourceLocation Location;
84+
StringRef Module;
85+
};
86+
87+
struct ExportDecl {
88+
ModuleId Id;
89+
SourceLocation Location;
90+
bool Wildcard; /// True if the last element of the ModuleId is '*'.
91+
};
92+
93+
struct ExportAsDecl {
94+
SourceLocation Location;
95+
ModuleId Id;
96+
};
97+
98+
struct ExternModuleDecl {
99+
SourceLocation Location;
100+
ModuleId Id;
101+
StringRef Path;
102+
};
103+
104+
struct UseDecl {
105+
SourceLocation Location;
106+
ModuleId Id;
107+
};
108+
109+
struct LinkDecl {
110+
StringRef Library;
111+
SourceLocation Location;
112+
LLVM_PREFERRED_TYPE(bool)
113+
unsigned Framework : 1;
114+
};
115+
116+
struct ConfigMacrosDecl {
117+
std::vector<StringRef> Macros;
118+
SourceLocation Location;
119+
LLVM_PREFERRED_TYPE(bool)
120+
unsigned Exhaustive : 1;
121+
};
122+
123+
struct ConflictDecl {
124+
SourceLocation Location;
125+
ModuleId Id;
126+
StringRef Message;
127+
};
128+
129+
using TopLevelDecl = std::variant<ModuleDecl, ExternModuleDecl>;
130+
131+
/// Represents the parsed form of a module map file.
132+
///
133+
/// This holds many reference types (StringRef, SourceLocation, etc.) whose
134+
/// lifetimes are bound by the SourceManager and FileManager used.
135+
struct ModuleMapFile {
136+
/// Beginning of the file, used for moduleMapFileRead callback.
137+
SourceLocation Start;
138+
std::vector<TopLevelDecl> Decls;
139+
140+
void dump(llvm::raw_ostream &out) const;
141+
};
142+
143+
/// Parse a module map file into an in memory representation.
144+
///
145+
/// \param ID a valid local FileID.
146+
/// \param Dir the directory in which this module map was found.
147+
/// \param SM the SourceManager for \a ID.
148+
/// \param Diags where to send the diagnostics.
149+
/// \param IsSystem was this module map found in a system search path.
150+
/// \param Offset optional offset into the buffer associated with \a ID. This is
151+
/// used for handling `#pragma clang module build`. Set to the end
152+
/// of the module map on return.
153+
///
154+
/// \returns The parsed ModuleMapFile if successful, std::nullopt otherwise.
155+
std::optional<ModuleMapFile>
156+
parseModuleMap(FileID ID, clang::DirectoryEntryRef Dir, SourceManager &SM,
157+
DiagnosticsEngine &Diags, bool IsSystem, unsigned *Offset);
158+
159+
} // namespace modulemap
160+
} // namespace clang
161+
162+
#endif

clang/lib/Lex/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_clang_library(clangLex
1616
MacroArgs.cpp
1717
MacroInfo.cpp
1818
ModuleMap.cpp
19+
ModuleMapFile.cpp
1920
PPCaching.cpp
2021
PPCallbacks.cpp
2122
PPConditionalDirectiveRecord.cpp

0 commit comments

Comments
 (0)