[flang] Update CommandTest for AIX (NFC) (#118403)
[llvm-project.git] / clang / lib / Basic / Module.cpp
blob330108d5b3e47f6047c9698f258022cda6bf8cfb
1 //===- Module.cpp - Describe a module -------------------------------------===//
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 // This file defines the Module class, which describes a module in the source
10 // code.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Basic/Module.h"
15 #include "clang/Basic/CharInfo.h"
16 #include "clang/Basic/FileManager.h"
17 #include "clang/Basic/LangOptions.h"
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/Basic/TargetInfo.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/ADT/StringMap.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/ADT/StringSwitch.h"
25 #include "llvm/Support/Compiler.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <functional>
31 #include <string>
32 #include <utility>
33 #include <vector>
35 using namespace clang;
37 Module::Module(ModuleConstructorTag, StringRef Name,
38 SourceLocation DefinitionLoc, Module *Parent, bool IsFramework,
39 bool IsExplicit, unsigned VisibilityID)
40 : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
41 VisibilityID(VisibilityID), IsUnimportable(false),
42 HasIncompatibleModuleFile(false), IsAvailable(true),
43 IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit),
44 IsSystem(false), IsExternC(false), IsInferred(false),
45 InferSubmodules(false), InferExplicitSubmodules(false),
46 InferExportWildcard(false), ConfigMacrosExhaustive(false),
47 NoUndeclaredIncludes(false), ModuleMapIsPrivate(false),
48 NamedModuleHasInit(true), NameVisibility(Hidden) {
49 if (Parent) {
50 IsAvailable = Parent->isAvailable();
51 IsUnimportable = Parent->isUnimportable();
52 IsSystem = Parent->IsSystem;
53 IsExternC = Parent->IsExternC;
54 NoUndeclaredIncludes = Parent->NoUndeclaredIncludes;
55 ModuleMapIsPrivate = Parent->ModuleMapIsPrivate;
57 Parent->SubModules.push_back(this);
61 Module::~Module() = default;
63 static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) {
64 StringRef Platform = Target.getPlatformName();
65 StringRef Env = Target.getTriple().getEnvironmentName();
67 // Attempt to match platform and environment.
68 if (Platform == Feature || Target.getTriple().getOSName() == Feature ||
69 Env == Feature)
70 return true;
72 auto CmpPlatformEnv = [](StringRef LHS, StringRef RHS) {
73 auto Pos = LHS.find('-');
74 if (Pos == StringRef::npos)
75 return false;
76 SmallString<128> NewLHS = LHS.slice(0, Pos);
77 NewLHS += LHS.slice(Pos+1, LHS.size());
78 return NewLHS == RHS;
81 SmallString<128> PlatformEnv = Target.getTriple().getOSAndEnvironmentName();
82 // Darwin has different but equivalent variants for simulators, example:
83 // 1. x86_64-apple-ios-simulator
84 // 2. x86_64-apple-iossimulator
85 // where both are valid examples of the same platform+environment but in the
86 // variant (2) the simulator is hardcoded as part of the platform name. Both
87 // forms above should match for "iossimulator" requirement.
88 if (Target.getTriple().isOSDarwin() && PlatformEnv.ends_with("simulator"))
89 return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature);
91 return PlatformEnv == Feature;
94 /// Determine whether a translation unit built using the current
95 /// language options has the given feature.
96 static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
97 const TargetInfo &Target) {
98 bool HasFeature = llvm::StringSwitch<bool>(Feature)
99 .Case("altivec", LangOpts.AltiVec)
100 .Case("blocks", LangOpts.Blocks)
101 .Case("coroutines", LangOpts.Coroutines)
102 .Case("cplusplus", LangOpts.CPlusPlus)
103 .Case("cplusplus11", LangOpts.CPlusPlus11)
104 .Case("cplusplus14", LangOpts.CPlusPlus14)
105 .Case("cplusplus17", LangOpts.CPlusPlus17)
106 .Case("cplusplus20", LangOpts.CPlusPlus20)
107 .Case("cplusplus23", LangOpts.CPlusPlus23)
108 .Case("cplusplus26", LangOpts.CPlusPlus26)
109 .Case("c99", LangOpts.C99)
110 .Case("c11", LangOpts.C11)
111 .Case("c17", LangOpts.C17)
112 .Case("c23", LangOpts.C23)
113 .Case("freestanding", LangOpts.Freestanding)
114 .Case("gnuinlineasm", LangOpts.GNUAsm)
115 .Case("objc", LangOpts.ObjC)
116 .Case("objc_arc", LangOpts.ObjCAutoRefCount)
117 .Case("opencl", LangOpts.OpenCL)
118 .Case("tls", Target.isTLSSupported())
119 .Case("zvector", LangOpts.ZVector)
120 .Default(Target.hasFeature(Feature) ||
121 isPlatformEnvironment(Target, Feature));
122 if (!HasFeature)
123 HasFeature = llvm::is_contained(LangOpts.ModuleFeatures, Feature);
124 return HasFeature;
127 bool Module::isUnimportable(const LangOptions &LangOpts,
128 const TargetInfo &Target, Requirement &Req,
129 Module *&ShadowingModule) const {
130 if (!IsUnimportable)
131 return false;
133 for (const Module *Current = this; Current; Current = Current->Parent) {
134 if (Current->ShadowingModule) {
135 ShadowingModule = Current->ShadowingModule;
136 return true;
138 for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
139 if (hasFeature(Current->Requirements[I].FeatureName, LangOpts, Target) !=
140 Current->Requirements[I].RequiredState) {
141 Req = Current->Requirements[I];
142 return true;
147 llvm_unreachable("could not find a reason why module is unimportable");
150 // The -fmodule-name option tells the compiler to textually include headers in
151 // the specified module, meaning Clang won't build the specified module. This
152 // is useful in a number of situations, for instance, when building a library
153 // that vends a module map, one might want to avoid hitting intermediate build
154 // products containing the module map or avoid finding the system installed
155 // modulemap for that library.
156 bool Module::isForBuilding(const LangOptions &LangOpts) const {
157 StringRef TopLevelName = getTopLevelModuleName();
158 StringRef CurrentModule = LangOpts.CurrentModule;
160 // When building the implementation of framework Foo, we want to make sure
161 // that Foo *and* Foo_Private are textually included and no modules are built
162 // for either.
163 if (!LangOpts.isCompilingModule() && getTopLevelModule()->IsFramework &&
164 CurrentModule == LangOpts.ModuleName &&
165 !CurrentModule.ends_with("_Private") &&
166 TopLevelName.ends_with("_Private"))
167 TopLevelName = TopLevelName.drop_back(8);
169 return TopLevelName == CurrentModule;
172 bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
173 Requirement &Req,
174 UnresolvedHeaderDirective &MissingHeader,
175 Module *&ShadowingModule) const {
176 if (IsAvailable)
177 return true;
179 if (isUnimportable(LangOpts, Target, Req, ShadowingModule))
180 return false;
182 // FIXME: All missing headers are listed on the top-level module. Should we
183 // just look there?
184 for (const Module *Current = this; Current; Current = Current->Parent) {
185 if (!Current->MissingHeaders.empty()) {
186 MissingHeader = Current->MissingHeaders.front();
187 return false;
191 llvm_unreachable("could not find a reason why module is unavailable");
194 bool Module::isSubModuleOf(const Module *Other) const {
195 for (auto *Parent = this; Parent; Parent = Parent->Parent) {
196 if (Parent == Other)
197 return true;
199 return false;
202 const Module *Module::getTopLevelModule() const {
203 const Module *Result = this;
204 while (Result->Parent)
205 Result = Result->Parent;
207 return Result;
210 static StringRef getModuleNameFromComponent(
211 const std::pair<std::string, SourceLocation> &IdComponent) {
212 return IdComponent.first;
215 static StringRef getModuleNameFromComponent(StringRef R) { return R; }
217 template<typename InputIter>
218 static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
219 bool AllowStringLiterals = true) {
220 for (InputIter It = Begin; It != End; ++It) {
221 if (It != Begin)
222 OS << ".";
224 StringRef Name = getModuleNameFromComponent(*It);
225 if (!AllowStringLiterals || isValidAsciiIdentifier(Name))
226 OS << Name;
227 else {
228 OS << '"';
229 OS.write_escaped(Name);
230 OS << '"';
235 template<typename Container>
236 static void printModuleId(raw_ostream &OS, const Container &C) {
237 return printModuleId(OS, C.begin(), C.end());
240 std::string Module::getFullModuleName(bool AllowStringLiterals) const {
241 SmallVector<StringRef, 2> Names;
243 // Build up the set of module names (from innermost to outermost).
244 for (const Module *M = this; M; M = M->Parent)
245 Names.push_back(M->Name);
247 std::string Result;
249 llvm::raw_string_ostream Out(Result);
250 printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
252 return Result;
255 bool Module::fullModuleNameIs(ArrayRef<StringRef> nameParts) const {
256 for (const Module *M = this; M; M = M->Parent) {
257 if (nameParts.empty() || M->Name != nameParts.back())
258 return false;
259 nameParts = nameParts.drop_back();
261 return nameParts.empty();
264 OptionalDirectoryEntryRef Module::getEffectiveUmbrellaDir() const {
265 if (const auto *Hdr = std::get_if<FileEntryRef>(&Umbrella))
266 return Hdr->getDir();
267 if (const auto *Dir = std::get_if<DirectoryEntryRef>(&Umbrella))
268 return *Dir;
269 return std::nullopt;
272 void Module::addTopHeader(FileEntryRef File) {
273 assert(File);
274 TopHeaders.insert(File);
277 ArrayRef<FileEntryRef> Module::getTopHeaders(FileManager &FileMgr) {
278 if (!TopHeaderNames.empty()) {
279 for (StringRef TopHeaderName : TopHeaderNames)
280 if (auto FE = FileMgr.getOptionalFileRef(TopHeaderName))
281 TopHeaders.insert(*FE);
282 TopHeaderNames.clear();
285 return llvm::ArrayRef(TopHeaders.begin(), TopHeaders.end());
288 bool Module::directlyUses(const Module *Requested) {
289 auto *Top = getTopLevelModule();
291 // A top-level module implicitly uses itself.
292 if (Requested->isSubModuleOf(Top))
293 return true;
295 for (auto *Use : Top->DirectUses)
296 if (Requested->isSubModuleOf(Use))
297 return true;
299 // Anyone is allowed to use our builtin stddef.h and its accompanying modules.
300 if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) ||
301 Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"}))
302 return true;
303 // Darwin is allowed is to use our builtin 'ptrauth.h' and its accompanying
304 // module.
305 if (!Requested->Parent && Requested->Name == "ptrauth")
306 return true;
308 if (NoUndeclaredIncludes)
309 UndeclaredUses.insert(Requested);
311 return false;
314 void Module::addRequirement(StringRef Feature, bool RequiredState,
315 const LangOptions &LangOpts,
316 const TargetInfo &Target) {
317 Requirements.push_back(Requirement{std::string(Feature), RequiredState});
319 // If this feature is currently available, we're done.
320 if (hasFeature(Feature, LangOpts, Target) == RequiredState)
321 return;
323 markUnavailable(/*Unimportable*/true);
326 void Module::markUnavailable(bool Unimportable) {
327 auto needUpdate = [Unimportable](Module *M) {
328 return M->IsAvailable || (!M->IsUnimportable && Unimportable);
331 if (!needUpdate(this))
332 return;
334 SmallVector<Module *, 2> Stack;
335 Stack.push_back(this);
336 while (!Stack.empty()) {
337 Module *Current = Stack.back();
338 Stack.pop_back();
340 if (!needUpdate(Current))
341 continue;
343 Current->IsAvailable = false;
344 Current->IsUnimportable |= Unimportable;
345 for (auto *Submodule : Current->submodules()) {
346 if (needUpdate(Submodule))
347 Stack.push_back(Submodule);
352 Module *Module::findSubmodule(StringRef Name) const {
353 // Add new submodules into the index.
354 for (unsigned I = SubModuleIndex.size(), E = SubModules.size(); I != E; ++I)
355 SubModuleIndex[SubModules[I]->Name] = I;
357 if (auto It = SubModuleIndex.find(Name); It != SubModuleIndex.end())
358 return SubModules[It->second];
360 return nullptr;
363 Module *Module::getGlobalModuleFragment() const {
364 assert(isNamedModuleUnit() && "We should only query the global module "
365 "fragment from the C++20 Named modules");
367 for (auto *SubModule : SubModules)
368 if (SubModule->isExplicitGlobalModule())
369 return SubModule;
371 return nullptr;
374 Module *Module::getPrivateModuleFragment() const {
375 assert(isNamedModuleUnit() && "We should only query the private module "
376 "fragment from the C++20 Named modules");
378 for (auto *SubModule : SubModules)
379 if (SubModule->isPrivateModule())
380 return SubModule;
382 return nullptr;
385 void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
386 // All non-explicit submodules are exported.
387 for (std::vector<Module *>::const_iterator I = SubModules.begin(),
388 E = SubModules.end();
389 I != E; ++I) {
390 Module *Mod = *I;
391 if (!Mod->IsExplicit)
392 Exported.push_back(Mod);
395 // Find re-exported modules by filtering the list of imported modules.
396 bool AnyWildcard = false;
397 bool UnrestrictedWildcard = false;
398 SmallVector<Module *, 4> WildcardRestrictions;
399 for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
400 Module *Mod = Exports[I].getPointer();
401 if (!Exports[I].getInt()) {
402 // Export a named module directly; no wildcards involved.
403 Exported.push_back(Mod);
405 continue;
408 // Wildcard export: export all of the imported modules that match
409 // the given pattern.
410 AnyWildcard = true;
411 if (UnrestrictedWildcard)
412 continue;
414 if (Module *Restriction = Exports[I].getPointer())
415 WildcardRestrictions.push_back(Restriction);
416 else {
417 WildcardRestrictions.clear();
418 UnrestrictedWildcard = true;
422 // If there were any wildcards, push any imported modules that were
423 // re-exported by the wildcard restriction.
424 if (!AnyWildcard)
425 return;
427 for (unsigned I = 0, N = Imports.size(); I != N; ++I) {
428 Module *Mod = Imports[I];
429 bool Acceptable = UnrestrictedWildcard;
430 if (!Acceptable) {
431 // Check whether this module meets one of the restrictions.
432 for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
433 Module *Restriction = WildcardRestrictions[R];
434 if (Mod == Restriction || Mod->isSubModuleOf(Restriction)) {
435 Acceptable = true;
436 break;
441 if (!Acceptable)
442 continue;
444 Exported.push_back(Mod);
448 void Module::buildVisibleModulesCache() const {
449 assert(VisibleModulesCache.empty() && "cache does not need building");
451 // This module is visible to itself.
452 VisibleModulesCache.insert(this);
454 // Every imported module is visible.
455 SmallVector<Module *, 16> Stack(Imports.begin(), Imports.end());
456 while (!Stack.empty()) {
457 Module *CurrModule = Stack.pop_back_val();
459 // Every module transitively exported by an imported module is visible.
460 if (VisibleModulesCache.insert(CurrModule).second)
461 CurrModule->getExportedModules(Stack);
465 void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const {
466 OS.indent(Indent);
467 if (IsFramework)
468 OS << "framework ";
469 if (IsExplicit)
470 OS << "explicit ";
471 OS << "module ";
472 printModuleId(OS, &Name, &Name + 1);
474 if (IsSystem || IsExternC) {
475 OS.indent(Indent + 2);
476 if (IsSystem)
477 OS << " [system]";
478 if (IsExternC)
479 OS << " [extern_c]";
482 OS << " {\n";
484 if (!Requirements.empty()) {
485 OS.indent(Indent + 2);
486 OS << "requires ";
487 for (unsigned I = 0, N = Requirements.size(); I != N; ++I) {
488 if (I)
489 OS << ", ";
490 if (!Requirements[I].RequiredState)
491 OS << "!";
492 OS << Requirements[I].FeatureName;
494 OS << "\n";
497 if (std::optional<Header> H = getUmbrellaHeaderAsWritten()) {
498 OS.indent(Indent + 2);
499 OS << "umbrella header \"";
500 OS.write_escaped(H->NameAsWritten);
501 OS << "\"\n";
502 } else if (std::optional<DirectoryName> D = getUmbrellaDirAsWritten()) {
503 OS.indent(Indent + 2);
504 OS << "umbrella \"";
505 OS.write_escaped(D->NameAsWritten);
506 OS << "\"\n";
509 if (!ConfigMacros.empty() || ConfigMacrosExhaustive) {
510 OS.indent(Indent + 2);
511 OS << "config_macros ";
512 if (ConfigMacrosExhaustive)
513 OS << "[exhaustive]";
514 for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) {
515 if (I)
516 OS << ", ";
517 OS << ConfigMacros[I];
519 OS << "\n";
522 struct {
523 StringRef Prefix;
524 HeaderKind Kind;
525 } Kinds[] = {{"", HK_Normal},
526 {"textual ", HK_Textual},
527 {"private ", HK_Private},
528 {"private textual ", HK_PrivateTextual},
529 {"exclude ", HK_Excluded}};
531 for (auto &K : Kinds) {
532 assert(&K == &Kinds[K.Kind] && "kinds in wrong order");
533 for (auto &H : getHeaders(K.Kind)) {
534 OS.indent(Indent + 2);
535 OS << K.Prefix << "header \"";
536 OS.write_escaped(H.NameAsWritten);
537 OS << "\" { size " << H.Entry.getSize()
538 << " mtime " << H.Entry.getModificationTime() << " }\n";
541 for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) {
542 for (auto &U : *Unresolved) {
543 OS.indent(Indent + 2);
544 OS << Kinds[U.Kind].Prefix << "header \"";
545 OS.write_escaped(U.FileName);
546 OS << "\"";
547 if (U.Size || U.ModTime) {
548 OS << " {";
549 if (U.Size)
550 OS << " size " << *U.Size;
551 if (U.ModTime)
552 OS << " mtime " << *U.ModTime;
553 OS << " }";
555 OS << "\n";
559 if (!ExportAsModule.empty()) {
560 OS.indent(Indent + 2);
561 OS << "export_as" << ExportAsModule << "\n";
564 for (auto *Submodule : submodules())
565 // Print inferred subframework modules so that we don't need to re-infer
566 // them (requires expensive directory iteration + stat calls) when we build
567 // the module. Regular inferred submodules are OK, as we need to look at all
568 // those header files anyway.
569 if (!Submodule->IsInferred || Submodule->IsFramework)
570 Submodule->print(OS, Indent + 2, Dump);
572 for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
573 OS.indent(Indent + 2);
574 OS << "export ";
575 if (Module *Restriction = Exports[I].getPointer()) {
576 OS << Restriction->getFullModuleName(true);
577 if (Exports[I].getInt())
578 OS << ".*";
579 } else {
580 OS << "*";
582 OS << "\n";
585 for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) {
586 OS.indent(Indent + 2);
587 OS << "export ";
588 printModuleId(OS, UnresolvedExports[I].Id);
589 if (UnresolvedExports[I].Wildcard)
590 OS << (UnresolvedExports[I].Id.empty() ? "*" : ".*");
591 OS << "\n";
594 if (Dump) {
595 for (Module *M : Imports) {
596 OS.indent(Indent + 2);
597 llvm::errs() << "import " << M->getFullModuleName() << "\n";
601 for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
602 OS.indent(Indent + 2);
603 OS << "use ";
604 OS << DirectUses[I]->getFullModuleName(true);
605 OS << "\n";
608 for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) {
609 OS.indent(Indent + 2);
610 OS << "use ";
611 printModuleId(OS, UnresolvedDirectUses[I]);
612 OS << "\n";
615 for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
616 OS.indent(Indent + 2);
617 OS << "link ";
618 if (LinkLibraries[I].IsFramework)
619 OS << "framework ";
620 OS << "\"";
621 OS.write_escaped(LinkLibraries[I].Library);
622 OS << "\"";
625 for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) {
626 OS.indent(Indent + 2);
627 OS << "conflict ";
628 printModuleId(OS, UnresolvedConflicts[I].Id);
629 OS << ", \"";
630 OS.write_escaped(UnresolvedConflicts[I].Message);
631 OS << "\"\n";
634 for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
635 OS.indent(Indent + 2);
636 OS << "conflict ";
637 OS << Conflicts[I].Other->getFullModuleName(true);
638 OS << ", \"";
639 OS.write_escaped(Conflicts[I].Message);
640 OS << "\"\n";
643 if (InferSubmodules) {
644 OS.indent(Indent + 2);
645 if (InferExplicitSubmodules)
646 OS << "explicit ";
647 OS << "module * {\n";
648 if (InferExportWildcard) {
649 OS.indent(Indent + 4);
650 OS << "export *\n";
652 OS.indent(Indent + 2);
653 OS << "}\n";
656 OS.indent(Indent);
657 OS << "}\n";
660 LLVM_DUMP_METHOD void Module::dump() const {
661 print(llvm::errs(), 0, true);
664 void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
665 VisibleCallback Vis, ConflictCallback Cb) {
666 // We can't import a global module fragment so the location can be invalid.
667 assert((M->isGlobalModule() || Loc.isValid()) &&
668 "setVisible expects a valid import location");
669 if (isVisible(M))
670 return;
672 ++Generation;
674 struct Visiting {
675 Module *M;
676 Visiting *ExportedBy;
679 std::function<void(Visiting)> VisitModule = [&](Visiting V) {
680 // Nothing to do for a module that's already visible.
681 unsigned ID = V.M->getVisibilityID();
682 if (ImportLocs.size() <= ID)
683 ImportLocs.resize(ID + 1);
684 else if (ImportLocs[ID].isValid())
685 return;
687 ImportLocs[ID] = Loc;
688 Vis(V.M);
690 // Make any exported modules visible.
691 SmallVector<Module *, 16> Exports;
692 V.M->getExportedModules(Exports);
693 for (Module *E : Exports) {
694 // Don't import non-importable modules.
695 if (!E->isUnimportable())
696 VisitModule({E, &V});
699 for (auto &C : V.M->Conflicts) {
700 if (isVisible(C.Other)) {
701 llvm::SmallVector<Module*, 8> Path;
702 for (Visiting *I = &V; I; I = I->ExportedBy)
703 Path.push_back(I->M);
704 Cb(Path, C.Other, C.Message);
708 VisitModule({M, nullptr});