clang: lib/Sema/SemaModule.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
21#include "llvm/ADT/StringExtras.h"
22
23using namespace clang;
24using namespace sema;
25
28 bool FromInclude = false) {
30
31 if (auto *LSD = dyn_cast(DC)) {
32 switch (LSD->getLanguage()) {
35 ExternCLoc = LSD->getBeginLoc();
36 break;
38 break;
39 }
41 }
42
45
48 ? diag::ext_module_import_not_at_top_level_noop
49 : diag::err_module_import_not_at_top_level_fatal)
52 diag::note_module_import_not_at_top_level)
53 << DC;
55 S.Diag(ImportLoc, diag::ext_module_import_in_extern_c)
57 S.Diag(ExternCLoc, diag::note_extern_c_begins_here);
58 }
59}
60
61
62
63
64
66 std::string Name;
67 if (Path.empty())
68 return Name;
69
70 for (auto &Piece : Path) {
71 if (!Name.empty())
72 Name += ".";
73 Name += Piece.getIdentifierInfo()->getName();
74 }
75 return Name;
76}
77
78
79
80
81
82
83
84
85static bool
87 Module *CurrentModule,
88 Module *&FoundPrimaryModuleInterface) {
90 return false;
91
92
93
95 return true;
96
97
98
99 if (FoundPrimaryModuleInterface)
100 return Imported == FoundPrimaryModuleInterface;
101
102 if (!CurrentModule)
103 return false;
104
105
106
107
108
109
110
112 return false;
113
115 assert(!FoundPrimaryModuleInterface ||
116 FoundPrimaryModuleInterface == Imported);
117 FoundPrimaryModuleInterface = Imported;
118 return true;
119 }
120
121 return false;
122}
123
124
125
126
127
128
129
130static void
134 bool IsImportingPrimaryModuleInterface = false) {
136 "'makeTransitiveImportsVisible()' is intended for standard C++ named "
137 "modules only.");
138
141 Worklist.push_back(Imported);
142
143 Module *FoundPrimaryModuleInterface =
144 IsImportingPrimaryModuleInterface ? Imported : nullptr;
145
146 while (!Worklist.empty()) {
147 Module *Importing = Worklist.pop_back_val();
148
149 if (Visited.count(Importing))
150 continue;
151 Visited.insert(Importing);
152
153
154
155 VisibleModules.setVisible(Importing, ImportLoc);
156
158 FoundPrimaryModuleInterface)) {
160 Worklist.push_back(TransImported);
161
162 for (auto [Exports, _] : Importing->Exports)
163 Worklist.push_back(Exports);
164 }
165 }
166}
167
170
171 Module *GlobalModule =
172 PushGlobalModuleFragment(ModuleLoc);
173
174
175 auto *TU = Context.getTranslationUnitDecl();
176
177
178
179
180
181
182
184 TU->setLocalOwningModule(GlobalModule);
185
186
187 return nullptr;
188}
189
190void Sema::HandleStartOfHeaderUnit() {
192 "Header units are only valid for C++20 modules");
194 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
195
197 if (HUName.empty()) {
198 HUName =
199 SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID())->getName();
201 }
202
203
204
205
206 auto F = SourceMgr.getFileManager().getOptionalFileRef(HUName);
207
208
209
210 if (!F)
211 F = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID());
212 assert(F && "failed to find the header unit source?");
214 auto &Map = PP.getHeaderSearchInfo().getModuleMap();
215 Module *Mod = Map.createHeaderUnit(StartOfTU, HUName, H);
216 assert(Mod && "module creation should not fail");
217 ModuleScopes.push_back({});
218 ModuleScopes.back().BeginLoc = StartOfTU;
219 ModuleScopes.back().Module = Mod;
220 VisibleModules.setVisible(Mod, StartOfTU);
221
222
223
224 auto *TU = Context.getTranslationUnitDecl();
226 TU->setLocalOwningModule(Mod);
227}
228
229
230
231
234 enum {
237 Reserved = 1,
238 } Reason = Valid;
239
240 if (II->isStr("module") || II->isStr("import"))
244 Reason = Reserved;
245
246
247
248
251
252 switch (Reason) {
254 return false;
256 return S.Diag(Loc, diag::err_invalid_module_name) << II;
257 case Reserved:
258 S.Diag(Loc, diag::warn_reserved_module_name) << II;
259 return false;
260 }
261 llvm_unreachable("fell off a fully covered switch");
262}
263
268 bool SeenNoTrivialPPDirective) {
270 "should only have module decl in standard C++ modules");
271
274
275
277
278 bool IsPartition = !Partition.empty();
279 if (IsPartition)
280 switch (MDK) {
283 break;
286 break;
287 default:
288 llvm_unreachable("how did we get a partition type set?");
289 }
290
291
292
293
294
295
296 switch (getLangOpts().getCompilingModule()) {
298
299 break;
300
303 break;
304
305
306
307 Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
310 break;
311
313 Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
314 return nullptr;
315
317 Diag(ModuleLoc, diag::err_module_decl_in_header_unit);
318 return nullptr;
319 }
320
321 assert(ModuleScopes.size() <= 1 && "expected to be at global module scope");
322
323
324
325
326
327 if (isCurrentModulePurview()) {
328 Diag(ModuleLoc, diag::err_module_redeclaration);
329 Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
330 diag::note_prev_module_declaration);
331 return nullptr;
332 }
333
334 assert((().CPlusPlusModules ||
335 SeenGMF == (bool)this->TheGlobalModuleFragment) &&
336 "mismatched global module state");
337
338
339
341 (!IsFirstDecl || SeenNoTrivialPPDirective) && !SeenGMF) {
342 Diag(ModuleLoc, diag::err_module_decl_not_at_start);
344 Diag(BeginLoc, diag::note_global_module_introducer_missing)
346 }
347
348
349
350
351
352
353
354
355
356
357 StringRef FirstComponentName = Path[0].getIdentifierInfo()->getName();
358 if (().isInSystemHeader(Path[0].getLoc()) &&
359 (FirstComponentName == "std" ||
360 (FirstComponentName.starts_with("std") &&
361 llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit))))
362 Diag(Path[0].getLoc(), diag::warn_reserved_module_name)
363 << Path[0].getIdentifierInfo();
364
365
366
367 for (auto Part : Path) {
369 return nullptr;
370 }
371
372
373
374
376 if (IsPartition) {
377 ModuleName += ":";
379 }
380
381
382 if (().CurrentModule.empty() &&
383 getLangOpts().CurrentModule != ModuleName) {
384 Diag(Path.front().getLoc(), diag::err_current_module_name_mismatch)
385 << SourceRange(Path.front().getLoc(), IsPartition
386 ? Partition.back().getLoc()
387 : Path.back().getLoc())
389 return nullptr;
390 }
392
393 auto &Map = PP.getHeaderSearchInfo().getModuleMap();
394 Module *Mod;
395 Module *Interface = nullptr;
396 switch (MDK) {
399
400
401 if (auto *M = Map.findOrLoadModule(ModuleName)) {
402 Diag(Path[0].getLoc(), diag::err_module_redefinition) << ModuleName;
403 if (M->DefinitionLoc.isValid())
404 Diag(M->DefinitionLoc, diag::note_prev_module_definition);
406 Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
407 << FE->getName();
408 Mod = M;
409 break;
410 }
411
412
413 Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
416 assert(Mod && "module creation should not fail");
417 break;
418 }
419
421
422
423
424
426 PP.getIdentifierInfo(ModuleName));
427
428
429
430
431
435 false);
437
439 Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
440
441 Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
442 } else {
443 Mod = Map.createModuleForImplementationUnit(ModuleLoc, ModuleName);
444 }
445 } break;
446
448
449
450 Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
452 break;
453 }
454
455 if (!this->TheGlobalModuleFragment) {
456 ModuleScopes.push_back({});
457 if (getLangOpts().ModulesLocalVisibility)
458 ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
459 } else {
460
462 }
463
464
465 ModuleScopes.back().BeginLoc = StartLoc;
466 ModuleScopes.back().Module = Mod;
467 VisibleModules.setVisible(Mod, ModuleLoc);
468
469
470
471
472
473
474 auto *TU = Context.getTranslationUnitDecl();
476 TU->setLocalOwningModule(Mod);
477
478
479
481
483
485 Listener->EnteringModulePurview();
486
487
488
489
491 HadImportedNamedModules = true;
492
494 Mod, ModuleLoc,
495 true);
496
497
501
502
503
504 Context.addModuleInitializer(ModuleScopes.back().Module, Import);
506
508
509
511 }
512
513 return nullptr;
514}
515
519
520
521
523 : ModuleScopes.back().Module->Kind) {
530 Diag(PrivateLoc, diag::err_private_module_fragment_not_module);
531 return nullptr;
532
534 Diag(PrivateLoc, diag::err_private_module_fragment_redefined);
535 Diag(ModuleScopes.back().BeginLoc, diag::note_previous_definition);
536 return nullptr;
537
539 Diag(PrivateLoc, diag::err_private_module_fragment_not_module_interface);
540 Diag(ModuleScopes.back().BeginLoc,
541 diag::note_not_module_interface_add_export)
543 return nullptr;
544
546 break;
547 }
548
549
550
551
552
553
555
556 auto &Map = PP.getHeaderSearchInfo().getModuleMap();
557 Module *PrivateModuleFragment =
558 Map.createPrivateModuleFragmentForInterfaceUnit(
559 ModuleScopes.back().Module, PrivateLoc);
560 assert(PrivateModuleFragment && "module creation should not fail");
561
562
563 ModuleScopes.push_back({});
564 ModuleScopes.back().BeginLoc = ModuleLoc;
565 ModuleScopes.back().Module = PrivateModuleFragment;
566 VisibleModules.setVisible(PrivateModuleFragment, ModuleLoc);
567
568
569
570
571 auto *TU = Context.getTranslationUnitDecl();
573 TU->setLocalOwningModule(PrivateModuleFragment);
574
575
576 return nullptr;
577}
578
582 bool IsPartition) {
583 assert((!IsPartition || getLangOpts().CPlusPlusModules) &&
584 "partition seen in non-C++20 code?");
585
586
587
589
590 std::string ModuleName;
591 if (IsPartition) {
592
593 assert(!ModuleScopes.empty() && "in a module purview, but no module?");
594 Module *NamedMod = ModuleScopes.back().Module;
595
596
598 ModuleName += ":";
600 ModuleNameLoc =
601 IdentifierLoc(Path[0].getLoc(), PP.getIdentifierInfo(ModuleName));
603 } else if (getLangOpts().CPlusPlusModules) {
605 ModuleNameLoc =
606 IdentifierLoc(Path[0].getLoc(), PP.getIdentifierInfo(ModuleName));
608 }
609
610
611
612
613
614
615
616
617 if (getLangOpts().CPlusPlusModules && isCurrentModulePurview() &&
619 Diag(ImportLoc, diag::err_module_self_import_cxx20)
621 return true;
622 }
623
625 ImportLoc, Path, Module::AllVisible, false);
626 if (!Mod)
627 return true;
628
631 Diag(ImportLoc, diag::err_module_import_non_interface_nor_parition)
632 << ModuleName;
633 return true;
634 }
635
636 return ActOnModuleImport(StartLoc, ExportLoc, ImportLoc, Mod, Path);
637}
638
639
642 if (auto *ED = dyn_cast(DC))
643 return ED;
644 return nullptr;
645}
646
652 Diag(ImportLoc, diag::warn_experimental_header_unit);
653
657 else
658 VisibleModules.setVisible(Mod, ImportLoc);
659
661 "We can only import a partition unit in a named module.");
664 Diag(ImportLoc,
665 diag::warn_import_implementation_partition_unit_in_interface_unit)
666 << Mod->Name;
667
669
670
671
672
673
676 ? diag::err_module_self_import
677 : diag::err_module_import_in_implementation)
679 }
680
682
683 if (Path.empty()) {
684
685
686
687 for (Module *ModCheck = Mod; ModCheck; ModCheck = ModCheck->Parent)
690
691 IdentifierLocs.push_back(Path[0].getLoc());
692 } else {
693 Module *ModCheck = Mod;
694 for (unsigned I = 0, N = Path.size(); I != N; ++I) {
695
696
697 if (!ModCheck)
698 break;
699 ModCheck = ModCheck->Parent;
700
701 IdentifierLocs.push_back(Path[I].getLoc());
702 }
703 }
704
706 Mod, IdentifierLocs);
708
709
710
711 if (!ModuleScopes.empty())
712 Context.addModuleInitializer(ModuleScopes.back().Module, Import);
713
714
717 Diag(ExportLoc, diag::err_export_partition_impl)
718 << SourceRange(ExportLoc, Path.back().getLoc());
719 } else if (ExportLoc.isValid() &&
721
722
723
724 Diag(ExportLoc, diag::err_export_not_in_module_interface);
725 } else if (!ModuleScopes.empty()) {
726
727
728
731 else
733 }
734
735 HadImportedNamedModules = true;
736
737 return Import;
738}
739
744
746
747
748
749
750
751 bool IsInModuleIncludes =
754
755
756
757 if (getLangOpts().Modules && !IsInModuleIncludes) {
760 DirectiveLoc, Mod,
761 DirectiveLoc);
762 if (!ModuleScopes.empty())
763 Context.addModuleInitializer(ModuleScopes.back().Module, ImportD);
765 Consumer.HandleImplicitImportDecl(ImportD);
766 }
767
769 VisibleModules.setVisible(Mod, DirectiveLoc);
770
772 Module *ThisModule = PP.getHeaderSearchInfo().lookupModule(
773 getLangOpts().CurrentModule, DirectiveLoc, false, false);
774 (void)ThisModule;
775
776
777 assert((getLangOpts().getCompilingModule() ==
779 ThisModule) &&
780 "was expecting a module if building a Clang module");
781 }
782}
783
786
787 ModuleScopes.push_back({});
788 ModuleScopes.back().Module = Mod;
789 if (getLangOpts().ModulesLocalVisibility)
790 ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
791
792 VisibleModules.setVisible(Mod, DirectiveLoc);
793
794
795
796
797 if (getLangOpts().trackLocalOwningModule()) {
798 for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
799 cast(DC)->setModuleOwnershipKind(
803 cast(DC)->setLocalOwningModule(Mod);
804 }
805 }
806}
807
809 if (getLangOpts().ModulesLocalVisibility) {
810 VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules);
811
812
814 }
815
816 assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod &&
817 "left the wrong module scope");
818 ModuleScopes.pop_back();
819
820
821
825
827 "end of submodule in main source file");
829 } else {
830
831 DirectiveLoc = EomLoc;
832 }
834
835
836 if (getLangOpts().trackLocalOwningModule()) {
837
838
839 for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) {
842 cast(DC)->setModuleOwnershipKind(
844 }
845 }
846}
847
850
852 VisibleModules.isVisible(Mod))
853 return;
854
855
858 Loc, Mod, Loc);
860 Consumer.HandleImplicitImportDecl(ImportD);
861
862
864 VisibleModules.setVisible(Mod, Loc);
865}
866
870
871
873
876
877
878
879
880
882 if (!isCurrentModulePurview()) {
883 Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
885 return D;
887 Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1;
888 Diag(ModuleScopes.back().BeginLoc,
889 diag::note_not_module_interface_add_export)
892 return D;
893 } else if (ModuleScopes.back().Module->Kind ==
895 Diag(ExportLoc, diag::err_export_in_private_module_fragment);
896 Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment);
898 return D;
899 }
900 }
901
903 if (const auto *ND = dyn_cast(DC)) {
904
905
906 if (ND->isAnonymousNamespace()) {
907 Diag(ExportLoc, diag::err_export_within_anonymous_namespace);
908 Diag(ND->getLocation(), diag::note_anonymous_namespace);
909
911 return D;
912 }
913
914
915
916
917
918
919 if (().HLSL && !DeferredExportedNamespaces.insert(ND).second)
920 break;
921 }
922 }
923
924
925
927 Diag(ExportLoc, diag::err_export_within_export);
928 if (ED->hasBraces())
929 Diag(ED->getLocation(), diag::note_export);
931 return D;
932 }
933
936
937 return D;
938}
939
941
942
945 bool AllUnnamed = true;
946 for (auto *D : DC->decls())
948 return AllUnnamed;
949}
950
951
953
954
956
958 S.Diag(D->getBeginLoc(), diag::err_hlsl_export_not_on_function);
960 return false;
961 }
962 }
963
964
965
966 bool HasName = false;
967 if (auto *ND = dyn_cast(D)) {
968
969
970 HasName = (bool)ND->getDeclName();
972 S.Diag(ND->getLocation(), diag::err_export_internal) << ND;
973 if (BlockStart.isValid())
974 S.Diag(BlockStart, diag::note_export);
975 return false;
976 }
977 }
978
979
980
981
982 if (auto *USD = dyn_cast(D)) {
986 S.Diag(USD->getLocation(), diag::err_export_using_internal)
988 S.Diag(Target->getLocation(), diag::note_using_decl_target);
989 if (BlockStart.isValid())
990 S.Diag(BlockStart, diag::note_export);
991 return false;
992 }
993 }
994
995
996
997 if (auto *DC = dyn_cast(D)) {
999 return true;
1000
1001 if (auto *ND = dyn_cast(D)) {
1002 if (!ND->getDeclName()) {
1003 S.Diag(ND->getLocation(), diag::err_export_anon_ns_internal);
1004 if (BlockStart.isValid())
1005 S.Diag(BlockStart, diag::note_export);
1006 return false;
1007 } else if (!DC->decls().empty() &&
1008 DC->getRedeclContext()->isFileContext()) {
1010 }
1011 }
1012 }
1013 return true;
1014}
1015
1018 if (RBraceLoc.isValid())
1019 ED->setRBraceLoc(RBraceLoc);
1020
1022
1025 ED->hasBraces() ? ED->getBeginLoc() : SourceLocation();
1026 for (auto *Child : ED->decls()) {
1028 if (auto *FD = dyn_cast(Child)) {
1029
1030
1031
1032
1033
1034
1035
1036 if (FD->isInlineSpecified() && !FD->isDefined())
1037 PendingInlineFuncDecls.insert(FD);
1038 }
1039 }
1040 }
1041
1042
1043 for (auto *Exported : ED->decls())
1045
1046 return D;
1047}
1048
1050
1051
1052 if (!TheGlobalModuleFragment) {
1056 }
1057
1058 assert(TheGlobalModuleFragment && "module creation should not fail");
1059
1060
1061 ModuleScopes.push_back({BeginLoc, TheGlobalModuleFragment,
1062 {}});
1063 VisibleModules.setVisible(TheGlobalModuleFragment, BeginLoc);
1064
1065 return TheGlobalModuleFragment;
1066}
1067
1068void Sema::PopGlobalModuleFragment() {
1069 assert(!ModuleScopes.empty() &&
1071 "left the wrong module scope, which is not global module fragment");
1072 ModuleScopes.pop_back();
1073}
1074
1076 if (!TheImplicitGlobalModuleFragment) {
1077 ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
1078 TheImplicitGlobalModuleFragment =
1081 }
1082 assert(TheImplicitGlobalModuleFragment && "module creation should not fail");
1083
1084
1085 ModuleScopes.push_back({BeginLoc, TheImplicitGlobalModuleFragment,
1086 {}});
1087 VisibleModules.setVisible(TheImplicitGlobalModuleFragment, BeginLoc);
1088 return TheImplicitGlobalModuleFragment;
1089}
1090
1091void Sema::PopImplicitGlobalModuleFragment() {
1092 assert(!ModuleScopes.empty() &&
1094 "left the wrong module scope, which is not global module fragment");
1095 ModuleScopes.pop_back();
1096}
1097
1098bool Sema::isCurrentModulePurview() const {
1100 return false;
1101
1102
1103
1111 return true;
1112 default:
1113 return false;
1114 }
1115}
1116
1117
1118
1119
1120
1121namespace {
1122class ExposureChecker {
1123public:
1124 ExposureChecker(Sema &S) : SemaRef(S) {}
1125
1126 bool checkExposure(const VarDecl *D, bool Diag);
1127 bool checkExposure(const CXXRecordDecl *D, bool Diag);
1128 bool checkExposure(const Stmt *S, bool Diag);
1129 bool checkExposure(const FunctionDecl *D, bool Diag);
1130 bool checkExposure(const NamedDecl *D, bool Diag);
1131 void checkExposureInContext(const DeclContext *DC);
1132 bool isExposureCandidate(const NamedDecl *D);
1133
1134 bool isTULocal(QualType Ty);
1135 bool isTULocal(const NamedDecl *ND);
1136 bool isTULocal(const Expr *E);
1137
1138 Sema &SemaRef;
1139
1140private:
1141 llvm::DenseSet<const NamedDecl *> ExposureSet;
1142 llvm::DenseSet<const NamedDecl *> KnownNonExposureSet;
1143};
1144
1145bool ExposureChecker::isTULocal(QualType Ty) {
1146
1147
1148
1149
1150
1152
1153
1154
1155
1156
1157
1158}
1159
1160bool ExposureChecker::isTULocal(const NamedDecl *D) {
1161 if (!D)
1162 return false;
1163
1164
1165
1166
1167
1168
1170 return true;
1171
1173 return true;
1174
1175
1176
1177
1179 if (auto *ND = dyn_cast(D->getDeclContext());
1180 ND && isTULocal(ND))
1181 return true;
1182
1183
1184
1185
1187 NamedDecl *PrimaryTemplate = nullptr;
1188 if (auto *CTSD = dyn_cast(D)) {
1189 TemplateArgs = CTSD->getTemplateArgs().asArray();
1190 PrimaryTemplate = CTSD->getSpecializedTemplate();
1191 if (isTULocal(PrimaryTemplate))
1192 return true;
1193 } else if (auto *VTSD = dyn_cast(D)) {
1194 TemplateArgs = VTSD->getTemplateArgs().asArray();
1195 PrimaryTemplate = VTSD->getSpecializedTemplate();
1196 if (isTULocal(PrimaryTemplate))
1197 return true;
1198 } else if (auto *FD = dyn_cast(D)) {
1199 if (auto *TAList = FD->getTemplateSpecializationArgs())
1200 TemplateArgs = TAList->asArray();
1201
1202 PrimaryTemplate = FD->getPrimaryTemplate();
1203 if (isTULocal(PrimaryTemplate))
1204 return true;
1205 }
1206
1207 if (!PrimaryTemplate)
1208
1209 return false;
1210
1211 if (KnownNonExposureSet.count(D))
1212 return false;
1213
1214 for (auto &TA : TemplateArgs) {
1215 switch (TA.getKind()) {
1217 if (isTULocal(TA.getAsType()))
1218 return true;
1219 break;
1221 if (isTULocal(TA.getAsDecl()))
1222 return true;
1223 break;
1224 default:
1225 break;
1226 }
1227 }
1228
1229
1230
1231
1232 if (ExposureSet.count(PrimaryTemplate) ||
1233 checkExposure(PrimaryTemplate, false))
1234 return true;
1235
1236
1237 KnownNonExposureSet.insert(D);
1238 return false;
1239}
1240
1241bool ExposureChecker::isTULocal(const Expr *E) {
1242 if (!E)
1243 return false;
1244
1245
1246
1247
1248 if (isTULocal(E->getType()))
1249 return true;
1250
1252
1253
1254
1255
1256
1257
1258
1259 if (const auto *DRE = dyn_cast(E)) {
1260 if (auto *FD = dyn_cast_or_null(DRE->getFoundDecl()))
1261 return isTULocal(FD);
1262 else if (auto *VD = dyn_cast_or_null(DRE->getFoundDecl()))
1263 return isTULocal(VD);
1264 else if (auto *RD = dyn_cast_or_null(DRE->getFoundDecl()))
1265 return isTULocal(RD);
1266 }
1267
1268
1269
1270
1271
1272 return false;
1273}
1274
1275bool ExposureChecker::isExposureCandidate(const NamedDecl *D) {
1276 if (!D)
1277 return false;
1278
1279
1280
1281
1282
1283
1285 if (!M)
1286 return false;
1287
1288
1291 assert(M && "Implicit global module must have a parent");
1292 }
1293
1295 return false;
1296
1298 return false;
1299
1300
1301
1302
1303
1304
1307 return false;
1308
1309 return true;
1310}
1311
1312bool ExposureChecker::checkExposure(const NamedDecl *D, bool Diag) {
1313 if (!isExposureCandidate(D))
1314 return false;
1315
1316 if (auto *FD = dyn_cast(D))
1317 return checkExposure(FD, Diag);
1318 if (auto *FTD = dyn_cast(D))
1319 return checkExposure(FTD->getTemplatedDecl(), Diag);
1320
1321 if (auto *VD = dyn_cast(D))
1322 return checkExposure(VD, Diag);
1323 if (auto *VTD = dyn_cast(D))
1324 return checkExposure(VTD->getTemplatedDecl(), Diag);
1325
1326 if (auto *RD = dyn_cast(D))
1327 return checkExposure(RD, Diag);
1328
1329 if (auto *CTD = dyn_cast(D))
1330 return checkExposure(CTD->getTemplatedDecl(), Diag);
1331
1332 return false;
1333}
1334
1335bool ExposureChecker::checkExposure(const FunctionDecl *FD, bool Diag) {
1336 bool IsExposure = false;
1338 IsExposure = true;
1341 diag::warn_exposure)
1343 }
1344
1346 if (isTULocal(Parms->getType())) {
1347 IsExposure = true;
1349 SemaRef.Diag(Parms->getLocation(), diag::warn_exposure)
1350 << Parms->getType();
1351 }
1352
1353 bool IsImplicitInstantiation =
1355
1356
1357
1358
1359
1360
1361
1362
1363
1366
1367 IsExposure |= checkExposure(FD->getBody(), Diag);
1368 if (IsExposure)
1369 ExposureSet.insert(FD);
1370
1371 return IsExposure;
1372}
1373
1374bool ExposureChecker::checkExposure(const VarDecl *VD, bool Diag) {
1375 bool IsExposure = false;
1376
1377
1378
1379
1380
1381
1383 IsExposure = true;
1387 }
1388
1389 if (isTULocal(VD->getType())) {
1390 IsExposure = true;
1392 SemaRef.Diag(VD->getLocation(), diag::warn_exposure) << VD->getType();
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402
1404 IsExposure |= checkExposure(VD->getInit(), Diag);
1405 if (IsExposure)
1406 ExposureSet.insert(VD);
1407
1408 return IsExposure;
1409}
1410
1411bool ExposureChecker::checkExposure(const CXXRecordDecl *RD, bool Diag) {
1413 return false;
1414
1415 bool IsExposure = false;
1417 IsExposure |= checkExposure(Method, Diag);
1418
1420 if (isTULocal(FD->getType())) {
1421 IsExposure = true;
1423 SemaRef.Diag(FD->getLocation(), diag::warn_exposure) << FD->getType();
1424 }
1425 }
1426
1428 if (isTULocal(Base.getType())) {
1429 IsExposure = true;
1431 SemaRef.Diag(Base.getBaseTypeLoc(), diag::warn_exposure)
1432 << Base.getType();
1433 }
1434 }
1435
1436 if (IsExposure)
1437 ExposureSet.insert(RD);
1438
1439 return IsExposure;
1440}
1441
1443public:
1444 using CallbackTy = std::function<void(DeclRefExpr *, ValueDecl *)>;
1445
1446 ReferenceTULocalChecker(ExposureChecker &C, CallbackTy &&Callback)
1447 : Checker(C), Callback(std::move(Callback)) {}
1448
1449 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
1450 ValueDecl *Referenced = DRE->getDecl();
1451 if (!Referenced)
1452 return true;
1453
1454 if (!Checker.isTULocal(Referenced))
1455
1456 return true;
1457
1459
1460
1461
1462
1463
1465 return true;
1466
1467
1468
1469
1470
1471
1472 ASTContext &Context = Referenced->getASTContext();
1474 if (DRE->isNonOdrUse() && (L == Linkage::Internal || L == Linkage::None))
1475 if (auto *VD = dyn_cast(Referenced);
1478 return true;
1479
1480 Callback(DRE, Referenced);
1481 return true;
1482 }
1483
1484 ExposureChecker &Checker;
1485 CallbackTy Callback;
1486};
1487
1488bool ExposureChecker::checkExposure(const Stmt *S, bool Diag) {
1489 if (!S)
1490 return false;
1491
1492 bool HasReferencedTULocals = false;
1493 ReferenceTULocalChecker Checker(
1494 *this, [this, &HasReferencedTULocals, Diag](DeclRefExpr *DRE,
1497 SemaRef.Diag(DRE->getExprLoc(), diag::warn_exposure) << Referenced;
1498 }
1499 HasReferencedTULocals = true;
1500 });
1501 Checker.TraverseStmt(const_cast<Stmt *>(S));
1502 return HasReferencedTULocals;
1503}
1504
1505void ExposureChecker::checkExposureInContext(const DeclContext *DC) {
1507 if (auto *Export = dyn_cast(TopD)) {
1508 checkExposureInContext(Export);
1509 continue;
1510 }
1511
1512 if (auto *LinkageSpec = dyn_cast(TopD)) {
1513 checkExposureInContext(LinkageSpec);
1514 continue;
1515 }
1516
1517 auto *TopND = dyn_cast(TopD);
1518 if (!TopND)
1519 continue;
1520
1521 if (auto *Namespace = dyn_cast(TopND)) {
1522 checkExposureInContext(Namespace);
1523 continue;
1524 }
1525
1526
1527
1528
1529
1530
1531 if (!TopND->isFromASTFile() && isExposureCandidate(TopND) &&
1532 !isTULocal(TopND))
1533 checkExposure(TopND, true);
1534 }
1535}
1536
1537}
1538
1540 if (!TU)
1541 return;
1542
1543 ExposureChecker Checker(*this);
1544
1547 Checker.checkExposureInContext(TU);
1548
1549
1550
1551
1552
1553 for (auto FDAndInstantiationLocPair : PendingCheckReferenceForTULocal) {
1554 FunctionDecl *FD = FDAndInstantiationLocPair.first;
1555 SourceLocation PointOfInstantiation = FDAndInstantiationLocPair.second;
1556
1558 continue;
1559
1560 ReferenceTULocalChecker(Checker, [&, this](DeclRefExpr *DRE,
1561 ValueDecl *Referenced) {
1562
1563
1564
1565
1566
1567
1569 return;
1570
1572 return;
1573
1574
1575
1576
1577
1580 return;
1581
1582 Diag(PointOfInstantiation,
1583 diag::warn_reference_tu_local_entity_in_other_tu)
1584 << FD << Referenced
1586 }).TraverseStmt(FD->getBody());
1587 }
1588}
1589
1590void Sema::checkReferenceToTULocalFromOtherTU(
1592
1593
1594 if (!FD || !HadImportedNamedModules)
1595 return;
1596
1597 PendingCheckReferenceForTULocal.push_back(
1598 std::make_pair(FD, PointOfInstantiation));
1599}
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
llvm::MachO::Target Target
Defines the clang::Preprocessor interface.
static void makeTransitiveImportsVisible(ASTContext &Ctx, VisibleModuleSet &VisibleModules, Module *Imported, Module *CurrentModule, SourceLocation ImportLoc, bool IsImportingPrimaryModuleInterface=false)
[module.import]p7: Additionally, when a module-import-declaration in a module unit of some module M i...
Definition SemaModule.cpp:131
static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II, SourceLocation Loc)
Tests whether the given identifier is reserved as a module name and diagnoses if it is.
Definition SemaModule.cpp:232
static const ExportDecl * getEnclosingExportDecl(const Decl *D)
Determine whether D is lexically within an export-declaration.
Definition SemaModule.cpp:640
static bool checkExportedDecl(Sema &, Decl *, SourceLocation)
Check that it's valid to export D.
Definition SemaModule.cpp:952
static std::string stringFromPath(ModuleIdPath Path)
Definition SemaModule.cpp:65
static void checkModuleImportContext(Sema &S, Module *M, SourceLocation ImportLoc, DeclContext *DC, bool FromInclude=false)
Definition SemaModule.cpp:26
static bool checkExportedDeclContext(Sema &S, DeclContext *DC, SourceLocation BlockStart)
Check that it's valid to export all the declarations in DC.
Definition SemaModule.cpp:943
static bool isImportingModuleUnitFromSameModule(ASTContext &Ctx, Module *Imported, Module *CurrentModule, Module *&FoundPrimaryModuleInterface)
Helper function for makeTransitiveImportsVisible to decide whether the.
Definition SemaModule.cpp:86
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
TranslationUnitDecl * getTranslationUnitDecl() const
void setCurrentNamedModule(Module *M)
Set the (C++20) module we are building.
bool isInSameModule(const Module *M1, const Module *M2) const
If the two module M1 and M2 are in the same module.
Represents a base class of a C++ class.
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
method_range methods() const
bool hasDefinition() const
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
DeclContext * getParent()
getParent - Returns the containing DeclContext.
bool isDependentContext() const
Determines whether this context is dependent on a template parameter.
DeclContext * getLexicalParent()
getLexicalParent - Returns the containing lexical DeclContext.
void addDecl(Decl *D)
Add the declaration D into this context.
decl_range noload_decls() const
noload_decls_begin/end - Iterate over the declarations stored in this context that are currently load...
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
A reference to a declared variable, function, enum, etc.
NonOdrUseReason isNonOdrUse() const
Is this expression a non-odr-use reference, and if so, why?
Decl - This represents one declaration (or definition), e.g.
FriendObjectKind getFriendObjectKind() const
Determines whether this declaration is the object of a friend declaration and, if so,...
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
bool isInAnotherModuleUnit() const
Whether this declaration comes from another module unit.
Module * getOwningModule() const
Get the module that owns this declaration (for visibility purposes).
bool isFromASTFile() const
Determine whether this declaration came from an AST file (such as a precompiled header or module) rat...
bool isInvalidDecl() const
SourceLocation getLocation() const
DeclContext * getDeclContext()
bool isInAnonymousNamespace() const
SourceLocation getBeginLoc() const LLVM_READONLY
DeclContext * getLexicalDeclContext()
getLexicalDeclContext - The declaration context where this Decl was lexically declared (LexicalDC).
@ VisibleWhenImported
This declaration has an owning module, and is visible when that module is imported.
@ Unowned
This declaration is not owned by a module.
@ ReachableWhenImported
This declaration has an owning module, and is visible to lookups that occurs within that module.
@ ModulePrivate
This declaration has an owning module, but is only visible to lookups that occur within that module.
@ Visible
This declaration has an owning module, but is globally visible (typically because its owning module i...
void setModuleOwnershipKind(ModuleOwnershipKind MOK)
Set whether this declaration is hidden from name lookup.
Represents a standard C++ module export declaration.
static ExportDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation ExportLoc)
void setRBraceLoc(SourceLocation L)
This represents one expression.
bool isValueDependent() const
Determines whether the value of this expression depends on.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit=nullptr) const
isConstantInitializer - Returns true if this expression can be emitted to IR as a constant,...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Represents a member of a struct/union/class.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
SourceRange getReturnTypeSourceRange() const
Attempt to compute an informative source range covering the function return type.
bool isInlined() const
Determine whether this function should be inlined, because it is either marked "inline" or "constexpr...
QualType getReturnType() const
ArrayRef< ParmVarDecl * > parameters() const
TemplateSpecializationKind getTemplateSpecializationKind() const
Determine what kind of template instantiation this function represents.
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
One of these records is kept for each identifier that is lexed.
ReservedIdentifierStatus isReserved(const LangOptions &LangOpts) const
Determine whether this is a name reserved for the implementation (C99 7.1.3, C++ [lib....
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
A simple pair of identifier info and location.
Describes a module import declaration, which makes the contents of the named module visible in the cu...
static ImportDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, ArrayRef< SourceLocation > IdentifierLocs)
Create a new module import declaration.
static ImportDecl * CreateImplicit(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, Module *Imported, SourceLocation EndLoc)
Create a new module import declaration for an implicitly-generated import.
@ CMK_None
Not compiling a module interface at all.
@ CMK_HeaderUnit
Compiling a module header unit.
@ CMK_ModuleMap
Compiling a module from a module map.
@ CMK_ModuleInterface
Compiling a C++ modules interface unit.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
std::string CurrentModule
The name of the current module, of which the main source file is a part.
virtual ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path, Module::NameVisibilityKind Visibility, bool IsInclusionDirective)=0
Attempt to load the given module.
virtual void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc)=0
Make the given module visible.
Module * createGlobalModuleFragmentForModuleUnit(SourceLocation Loc, Module *Parent=nullptr)
Create a global module fragment for a C++ module unit.
Module * createImplicitGlobalModuleFragmentForModuleUnit(SourceLocation Loc, Module *Parent)
Describes a module or submodule.
StringRef getTopLevelModuleName() const
Retrieve the name of the top-level module.
SmallVector< ExportDecl, 2 > Exports
The set of export declarations.
bool isForBuilding(const LangOptions &LangOpts) const
Determine whether this module can be built in this compilation.
bool isInterfaceOrPartition() const
bool isModulePartitionImplementation() const
Is this a module partition implementation unit.
@ AllVisible
All of the names in this module are visible.
Module(ModuleConstructorTag, StringRef Name, SourceLocation DefinitionLoc, Module *Parent, bool IsFramework, bool IsExplicit, unsigned VisibilityID)
Construct a new module or submodule.
Module * Parent
The parent of this module.
ModuleKind Kind
The kind of this module.
llvm::SmallSetVector< Module *, 2 > Imports
The set of modules imported by this module, and on which this module depends.
std::string Name
The name of this module.
unsigned IsExternC
Whether this is an 'extern "C"' module (which implicitly puts all headers in it within an 'extern "C"...
StringRef getPrimaryModuleInterfaceName() const
Get the primary module interface name from a partition.
bool isModulePartition() const
Is this a module partition.
bool isExplicitGlobalModule() const
bool isImplicitGlobalModule() const
bool isHeaderUnit() const
Is this module a header unit.
@ ModuleImplementationUnit
This is a C++20 module implementation unit.
@ ModuleMapModule
This is a module that was defined by a module map and built out of header files.
@ ImplicitGlobalModuleFragment
This is an implicit fragment of the global module which contains only language linkage declarations (...
@ ModulePartitionInterface
This is a C++20 module partition interface.
@ ModuleInterfaceUnit
This is a C++20 module interface unit.
@ ModuleHeaderUnit
This is a C++20 header unit.
@ ModulePartitionImplementation
This is a C++20 module partition implementation.
@ PrivateModuleFragment
This is the private module fragment within some C++ module.
@ ExplicitGlobalModuleFragment
This is the explicit Global Module Fragment of a modular TU.
std::string getFullModuleName(bool AllowStringLiterals=false) const
Retrieve the full name of this module, including the path from its top-level module.
bool isNamedModule() const
Does this Module is a named module of a standard named module?
This represents a decl that may have a name.
Linkage getLinkageInternal() const
Determine what kind of linkage this entity has.
Represents a parameter to a function.
HeaderSearch & getHeaderSearchInfo() const
A (possibly-)qualified type.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
field_range fields() const
Scope - A scope is a transient data structure that is used while parsing the program.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Sema - This implements semantic analysis and AST building for C.
void ActOnAnnotModuleBegin(SourceLocation DirectiveLoc, Module *Mod)
The parsed has entered a submodule.
Definition SemaModule.cpp:784
void ActOnAnnotModuleInclude(SourceLocation DirectiveLoc, Module *Mod)
The parser has processed a module import translated from a include or similar preprocessing directive...
Definition SemaModule.cpp:740
const TranslationUnitKind TUKind
The kind of translation unit we are processing.
@ PartitionImplementation
'module X:Y;'
@ Interface
'export module X;'
@ Implementation
'module X;'
@ PartitionInterface
'export module X:Y;'
llvm::DenseMap< NamedDecl *, NamedDecl * > VisibleNamespaceCache
Map from the most recent declaration of a namespace to the most recent visible declaration of that na...
void ActOnAnnotModuleEnd(SourceLocation DirectiveLoc, Module *Mod)
The parser has left a submodule.
Definition SemaModule.cpp:808
bool currentModuleIsImplementation() const
Is the module scope we are an implementation unit?
DeclResult ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, ModuleIdPath Path, bool IsPartition=false)
The parser has processed a module import declaration.
Definition SemaModule.cpp:579
DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType=nullptr)
ASTContext & getASTContext() const
Decl * ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, SourceLocation LBraceLoc)
We have parsed the start of an export declaration, including the '{' (if present).
Definition SemaModule.cpp:867
const LangOptions & getLangOpts() const
void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind)
DeclGroupPtrTy ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc)
The parser has processed a global-module-fragment declaration that begins the definition of the globa...
Definition SemaModule.cpp:169
DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, ModuleIdPath Partition, ModuleImportState &ImportState, bool SeenNoTrivialPPDirective)
The parser has processed a module-declaration that begins the definition of a module interface or imp...
Definition SemaModule.cpp:265
Module * getCurrentModule() const
Get the module unit whose scope we are currently within.
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, SourceLocation PrivateLoc)
The parser has processed a private-module-fragment declaration that begins the definition of the priv...
Definition SemaModule.cpp:517
SourceManager & getSourceManager() const
void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod)
Definition SemaModule.cpp:745
bool isModuleVisible(const Module *M, bool ModulePrivate=false)
bool isSFINAEContext() const
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
@ FirstDecl
Parsing the first decl in a TU.
@ GlobalFragment
after 'module;' but before 'module X;'
@ NotACXX20Module
Not a C++20 TU, or an invalid state was found.
@ ImportAllowed
after 'module X;' but before any non-import decl.
ModuleLoader & getModuleLoader() const
Retrieve the module loader associated with the preprocessor.
void PushDeclContext(Scope *S, DeclContext *DC)
Set the current declaration context until it gets popped.
Decl * ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc)
Complete the definition of an export declaration.
Definition SemaModule.cpp:1016
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
ASTMutationListener * getASTMutationListener() const
void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod)
Create an implicit import of the given module at the given source location, for error recovery,...
Definition SemaModule.cpp:848
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
SourceLocation getIncludeLoc(FileID FID) const
Returns the include location if FID is a #include'd file otherwise it returns an invalid location.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
bool isWrittenInMainFile(SourceLocation Loc) const
Returns true if the spelling location for the given location is in the main file buffer.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
Stmt - This represents one statement.
@ Declaration
The template argument is a declaration that was provided for a pointer, reference,...
@ Type
The template argument is a type.
The top declaration context.
Linkage getLinkage() const
Determine the linkage of this type.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
bool isInline() const
Whether this variable is (C++1z) inline.
const Expr * getInit() const
A set of visible modules.
void setVisible(Module *M, SourceLocation Loc, bool IncludeExports=true, VisibleCallback Vis=[](Module *) {}, ConflictCallback Cb=[](ArrayRef< Module * >, Module *, StringRef) {})
Make a specific module visible.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
ArrayRef< IdentifierLoc > ModuleIdPath
A sequence of identifier/location pairs used to describe a particular module or submodule,...
ActionResult< Decl * > DeclResult
Linkage
Describes the different kinds of linkage (C++ [basic.link], C99 6.2.2) that an entity may have.
@ None
No linkage, which means that the entity is unique and can only be referred to from within its scope.
@ Internal
Internal linkage, which indicates that the entity can be referred to from within the translation unit...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
@ Global
The global module fragment, between 'module;' and a module-declaration.
@ Normal
A normal translation unit fragment.
@ TU_ClangModule
The translation unit is a clang module.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
@ TSK_ImplicitInstantiation
This template specialization was implicitly instantiated from a template.
U cast(CodeGen::Address addr)
int const char * function