Skip to content

Commit c6b9298

Browse files
committed
[clang][cas] Create explicit IncludeTree::ModuleMap
Instead of putting the modulemap file in the include-tree filesystem and parsing it at build time, create a data structure that represents just the parts of the modulemap we need when building the module: * Flags (explicit, system, framework, etc.) * Exports (export *, export Foo) * LinkLibraries (implicit framework autolink, link Foo) Additionally, we add modular headers lazily by inserting known headers when we encounter an include-tree header that is part of a submodule (this is needed for missing #include diagnostics). This removes the possibility of mismatches between header paths seen during modulemap parsing from the paths we embed due to #includes, for exmaple due to VFS virtual vs external paths. (cherry picked from commit a237e68) Conflicts: clang/include/clang/Basic/Module.h clang/lib/Serialization/ASTWriter.cpp
1 parent fcf503d commit c6b9298

17 files changed

+878
-106
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ def err_missing_module_name : Error<
228228
DefaultFatal;
229229
def err_missing_module : Error<
230230
"no module named '%0' declared in module map file '%1'">, DefaultFatal;
231+
def err_missing_module_include_tree : Error<
232+
"no module named '%0' declared in include-tree module map '%1'">, DefaultFatal;
231233
def err_no_submodule : Error<"no submodule named %0 in module '%1'">;
232234
def err_no_submodule_suggest : Error<
233235
"no submodule named %0 in module '%1'; did you mean '%2'?">;

clang/include/clang/Basic/Module.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ class alignas(8) Module {
111111
/// of header files.
112112
ModuleMapModule,
113113

114+
/// This is a module that was defined by a module map and built out
115+
/// of header files as part of an \c IncludeTree.
116+
IncludeTreeModuleMap,
117+
114118
/// This is a C++ 20 header unit.
115119
ModuleHeaderUnit,
116120

@@ -204,7 +208,9 @@ class alignas(8) Module {
204208

205209
bool isPrivateModule() const { return Kind == PrivateModuleFragment; }
206210

207-
bool isModuleMapModule() const { return Kind == ModuleMapModule; }
211+
bool isModuleMapModule() const {
212+
return Kind == ModuleMapModule || Kind == IncludeTreeModuleMap;
213+
}
208214

209215
private:
210216
/// The submodules of this module, indexed by name.

clang/include/clang/CAS/IncludeTree.h

Lines changed: 260 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class IncludeTree : public IncludeTreeBase<IncludeTree> {
5454
class File;
5555
class FileList;
5656
class Node;
57+
class Module;
5758
class ModuleImport;
59+
class ModuleMap;
5860

5961
Expected<File> getBaseFile();
6062

@@ -381,6 +383,262 @@ class IncludeTree::Node {
381383
NodeKind K;
382384
};
383385

386+
/// Module or submodule declaration as part of the \c IncludeTreeRoot module
387+
/// map structure.
388+
class IncludeTree::Module : public IncludeTreeBase<Module> {
389+
public:
390+
static constexpr StringRef getNodeKind() { return "Modu"; }
391+
392+
class ExportList;
393+
class LinkLibraryList;
394+
395+
struct ModuleFlags {
396+
bool IsFramework : 1;
397+
bool IsExplicit : 1;
398+
bool IsExternC : 1;
399+
bool IsSystem : 1;
400+
ModuleFlags()
401+
: IsFramework(false), IsExplicit(false), IsExternC(false),
402+
IsSystem(false) {}
403+
};
404+
405+
ModuleFlags getFlags() const;
406+
407+
/// The name of the current (sub)module.
408+
StringRef getName() const { return dataAfterFlags(); }
409+
410+
size_t getNumSubmodules() const;
411+
412+
Expected<Module> getSubmodule(size_t I) {
413+
assert(I < getNumSubmodules());
414+
auto Node = getCAS().getProxy(getReference(I));
415+
if (!Node)
416+
return Node.takeError();
417+
return Module(*Node);
418+
}
419+
420+
llvm::Error forEachSubmodule(llvm::function_ref<llvm::Error(Module)> CB);
421+
422+
std::optional<ObjectRef> getExportsRef() const {
423+
if (std::optional<unsigned> Index = getExportsIndex())
424+
return getReference(*Index);
425+
return std::nullopt;
426+
}
427+
std::optional<ObjectRef> getLinkLibrariesRef() const {
428+
if (std::optional<unsigned> Index = getLinkLibrariesIndex())
429+
return getReference(*Index);
430+
return std::nullopt;
431+
}
432+
433+
/// The list of modules that this submodule re-exports.
434+
Expected<std::optional<ExportList>> getExports();
435+
436+
/// The list of modules that this submodule re-exports.
437+
Expected<std::optional<LinkLibraryList>> getLinkLibraries();
438+
439+
llvm::Error print(llvm::raw_ostream &OS, unsigned Indent = 0);
440+
441+
static Expected<Module> create(ObjectStore &DB, StringRef ModuleName,
442+
ModuleFlags Flags,
443+
ArrayRef<ObjectRef> Submodules,
444+
std::optional<ObjectRef> ExportList,
445+
std::optional<ObjectRef> LinkLibraries);
446+
447+
static bool isValid(const ObjectProxy &Node) {
448+
if (!IncludeTreeBase::isValid(Node))
449+
return false;
450+
IncludeTreeBase Base(Node);
451+
return Base.getData().size() > 1;
452+
}
453+
static bool isValid(ObjectStore &DB, ObjectRef Ref) {
454+
auto Node = DB.getProxy(Ref);
455+
if (!Node) {
456+
llvm::consumeError(Node.takeError());
457+
return false;
458+
}
459+
return isValid(*Node);
460+
}
461+
462+
private:
463+
char rawFlags() const { return getData()[0]; }
464+
StringRef dataAfterFlags() const { return getData().drop_front(); }
465+
bool hasExports() const;
466+
bool hasLinkLibraries() const;
467+
std::optional<unsigned> getExportsIndex() const;
468+
std::optional<unsigned> getLinkLibrariesIndex() const;
469+
470+
explicit Module(ObjectProxy Node) : IncludeTreeBase(std::move(Node)) {
471+
assert(isValid(*this));
472+
}
473+
474+
friend class IncludeTreeBase<Module>;
475+
friend class IncludeTreeRoot;
476+
friend class ModuleMap;
477+
};
478+
479+
/// The set of modules re-exported by another module.
480+
class IncludeTree::Module::ExportList : public IncludeTreeBase<ExportList> {
481+
public:
482+
static constexpr StringRef getNodeKind() { return "ExpL"; }
483+
484+
/// An explicit export.
485+
struct Export {
486+
StringRef ModuleName;
487+
bool Wildcard;
488+
};
489+
490+
/// Whether this module exports all imported modules (`export *`).
491+
bool hasGlobalWildcard() const;
492+
493+
size_t getNumExplicitExports() const { return getNumReferences(); }
494+
495+
/// Whether the explicit export at \p I has a wildcard (`export MyModule.*`).
496+
bool exportHasWildcard(size_t I) const;
497+
498+
Expected<Export> getExplicitExport(size_t I);
499+
500+
/// Calls \p CB for each explicit export declaration.
501+
llvm::Error forEachExplicitExport(llvm::function_ref<llvm::Error(Export)> CB);
502+
503+
llvm::Error print(llvm::raw_ostream &OS, unsigned Indent = 0);
504+
505+
static Expected<ExportList> create(ObjectStore &DB, ArrayRef<Export> Exports,
506+
bool GlobalWildcard);
507+
508+
static bool isValid(const ObjectProxy &Node) {
509+
if (!IncludeTreeBase::isValid(Node))
510+
return false;
511+
IncludeTreeBase Base(Node);
512+
size_t ExpectedBitSize = Base.getNumReferences() + 1;
513+
size_t ExpectedSize =
514+
ExpectedBitSize / 8 + (ExpectedBitSize % 8 == 0 ? 0 : 1);
515+
return Base.getData().size() == ExpectedSize;
516+
}
517+
static bool isValid(ObjectStore &DB, ObjectRef Ref) {
518+
auto Node = DB.getProxy(Ref);
519+
if (!Node) {
520+
llvm::consumeError(Node.takeError());
521+
return false;
522+
}
523+
return isValid(*Node);
524+
}
525+
526+
private:
527+
explicit ExportList(ObjectProxy Node) : IncludeTreeBase(std::move(Node)) {
528+
assert(isValid(*this));
529+
}
530+
531+
friend class IncludeTreeBase<ExportList>;
532+
friend class Module;
533+
};
534+
535+
/// The set of libraries to link against when using a module.
536+
class IncludeTree::Module::LinkLibraryList
537+
: public IncludeTreeBase<LinkLibraryList> {
538+
public:
539+
static constexpr StringRef getNodeKind() { return "LnkL"; }
540+
541+
struct LinkLibrary {
542+
StringRef Library;
543+
bool IsFramework;
544+
};
545+
546+
size_t getNumLibraries() const { return getNumReferences(); }
547+
548+
/// Whether the library at \p I is a framework.
549+
bool isFramework(size_t I) const;
550+
551+
ObjectRef getLibraryNameRef(size_t I) const { return getReference(I); }
552+
553+
Expected<LinkLibrary> getLinkLibrary(size_t I) {
554+
auto Name = getCAS().getProxy(getLibraryNameRef(I));
555+
if (!Name)
556+
return Name.takeError();
557+
return LinkLibrary{Name->getData(), isFramework(I)};
558+
}
559+
560+
/// Calls \p CB for each link libary.
561+
llvm::Error
562+
forEachLinkLibrary(llvm::function_ref<llvm::Error(LinkLibrary)> CB);
563+
564+
llvm::Error print(llvm::raw_ostream &OS, unsigned Indent = 0);
565+
566+
static Expected<LinkLibraryList> create(ObjectStore &DB,
567+
ArrayRef<LinkLibrary> Exports);
568+
569+
static bool isValid(const ObjectProxy &Node) {
570+
if (!IncludeTreeBase::isValid(Node))
571+
return false;
572+
IncludeTreeBase Base(Node);
573+
size_t ExpectedBitSize = Base.getNumReferences();
574+
size_t ExpectedSize =
575+
ExpectedBitSize / 8 + (ExpectedBitSize % 8 == 0 ? 0 : 1);
576+
return Base.getData().size() == ExpectedSize;
577+
}
578+
static bool isValid(ObjectStore &DB, ObjectRef Ref) {
579+
auto Node = DB.getProxy(Ref);
580+
if (!Node) {
581+
llvm::consumeError(Node.takeError());
582+
return false;
583+
}
584+
return isValid(*Node);
585+
}
586+
587+
private:
588+
explicit LinkLibraryList(ObjectProxy Node)
589+
: IncludeTreeBase(std::move(Node)) {
590+
assert(isValid(*this));
591+
}
592+
593+
friend class IncludeTreeBase<LinkLibraryList>;
594+
friend class Module;
595+
};
596+
597+
class IncludeTree::ModuleMap : public IncludeTreeBase<ModuleMap> {
598+
public:
599+
static constexpr StringRef getNodeKind() { return "ModM"; }
600+
601+
size_t getNumModules() const { return getNumReferences(); }
602+
603+
Expected<Module> getModule(size_t I) {
604+
auto Node = getCAS().getProxy(getReference(I));
605+
if (!Node)
606+
return Node.takeError();
607+
return Module(*Node);
608+
}
609+
610+
/// Calls \p CB for each module declaration.
611+
llvm::Error forEachModule(llvm::function_ref<llvm::Error(Module)> CB);
612+
613+
llvm::Error print(llvm::raw_ostream &OS, unsigned Indent = 0);
614+
615+
static Expected<ModuleMap> create(ObjectStore &DB,
616+
ArrayRef<ObjectRef> Modules);
617+
618+
static bool isValid(const ObjectProxy &Node) {
619+
if (!IncludeTreeBase::isValid(Node))
620+
return false;
621+
IncludeTreeBase Base(Node);
622+
return Base.getData().empty();
623+
}
624+
static bool isValid(ObjectStore &DB, ObjectRef Ref) {
625+
auto Node = DB.getProxy(Ref);
626+
if (!Node) {
627+
llvm::consumeError(Node.takeError());
628+
return false;
629+
}
630+
return isValid(*Node);
631+
}
632+
633+
private:
634+
explicit ModuleMap(ObjectProxy Node) : IncludeTreeBase(std::move(Node)) {
635+
assert(isValid(*this));
636+
}
637+
638+
friend class IncludeTreeBase<ModuleMap>;
639+
friend class IncludeTreeRoot;
640+
};
641+
384642
/// Represents the include-tree result for a translation unit.
385643
class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
386644
public:
@@ -426,12 +684,12 @@ class IncludeTreeRoot : public IncludeTreeBase<IncludeTreeRoot> {
426684
return std::nullopt;
427685
}
428686

429-
Expected<std::optional<IncludeTree::File>> getModuleMapFile() {
687+
Expected<std::optional<IncludeTree::ModuleMap>> getModuleMap() {
430688
if (std::optional<ObjectRef> Ref = getModuleMapRef()) {
431689
auto Node = getCAS().getProxy(*Ref);
432690
if (!Node)
433691
return Node.takeError();
434-
return IncludeTree::File(*Node);
692+
return IncludeTree::ModuleMap(*Node);
435693
}
436694
return std::nullopt;
437695
}

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ class FrontendInputFile {
246246
bool IsSystem = false)
247247
: File(File.str()), IncludeTree(std::move(Tree)), Kind(Kind),
248248
IsSystem(IsSystem) {}
249+
FrontendInputFile(cas::ObjectRef Tree, llvm::MemoryBufferRef Buffer,
250+
InputKind Kind, bool IsSystem = false)
251+
: Buffer(Buffer), IncludeTree(std::move(Tree)), Kind(Kind),
252+
IsSystem(IsSystem) {}
249253

250254
InputKind getKind() const { return Kind; }
251255
bool isSystem() const { return IsSystem; }

clang/lib/AST/Decl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,7 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
15961596

15971597
switch (M->Kind) {
15981598
case Module::ModuleMapModule:
1599+
case Module::IncludeTreeModuleMap:
15991600
// Module map modules have no special linkage semantics.
16001601
return nullptr;
16011602

0 commit comments

Comments
 (0)