@@ -73,6 +73,90 @@ static std::string stringFromPath(ModuleIdPath Path) {
73
73
return Name;
74
74
}
75
75
76
+ // / Helper function for makeTransitiveImportsVisible to decide whether
77
+ // / the \param Imported module unit is in the same module with the \param
78
+ // / CurrentModule.
79
+ // / \param FoundPrimaryModuleInterface is a helper parameter to record the
80
+ // / primary module interface unit corresponding to the module \param
81
+ // / CurrentModule. Since currently it is expensive to decide whether two module
82
+ // / units come from the same module by comparing the module name.
83
+ static bool
84
+ isImportingModuleUnitFromSameModule (Module *Imported, Module *CurrentModule,
85
+ Module *&FoundPrimaryModuleInterface) {
86
+ if (!Imported->isNamedModule ())
87
+ return false ;
88
+
89
+ // The a partition unit we're importing must be in the same module of the
90
+ // current module.
91
+ if (Imported->isModulePartition ())
92
+ return true ;
93
+
94
+ // If we found the primary module interface during the search process, we can
95
+ // return quickly to avoid expensive string comparison.
96
+ if (FoundPrimaryModuleInterface)
97
+ return Imported == FoundPrimaryModuleInterface;
98
+
99
+ if (!CurrentModule)
100
+ return false ;
101
+
102
+ // Then the imported module must be a primary module interface unit. It
103
+ // is only allowed to import the primary module interface unit from the same
104
+ // module in the implementation unit and the implementation partition unit.
105
+
106
+ // Since we'll handle implementation unit above. We can only care
107
+ // about the implementation partition unit here.
108
+ if (!CurrentModule->isModulePartitionImplementation ())
109
+ return false ;
110
+
111
+ if (Imported->getPrimaryModuleInterfaceName () ==
112
+ CurrentModule->getPrimaryModuleInterfaceName ()) {
113
+ assert (!FoundPrimaryModuleInterface ||
114
+ FoundPrimaryModuleInterface == Imported);
115
+ FoundPrimaryModuleInterface = Imported;
116
+ return true ;
117
+ }
118
+
119
+ return false ;
120
+ }
121
+
122
+ // / [module.import]p7:
123
+ // / Additionally, when a module-import-declaration in a module unit of some
124
+ // / module M imports another module unit U of M, it also imports all
125
+ // / translation units imported by non-exported module-import-declarations in
126
+ // / the module unit purview of U. These rules can in turn lead to the
127
+ // / importation of yet more translation units.
128
+ static void
129
+ makeTransitiveImportsVisible (VisibleModuleSet &VisibleModules, Module *Imported,
130
+ Module *CurrentModule, SourceLocation ImportLoc,
131
+ bool IsImportingPrimaryModuleInterface = false ) {
132
+ assert (Imported->isNamedModule () &&
133
+ " 'makeTransitiveImportsVisible()' is intended for standard C++ named "
134
+ " modules only." );
135
+
136
+ llvm::SmallVector<Module *, 4 > Worklist;
137
+ Worklist.push_back (Imported);
138
+
139
+ Module *FoundPrimaryModuleInterface =
140
+ IsImportingPrimaryModuleInterface ? Imported : nullptr ;
141
+
142
+ while (!Worklist.empty ()) {
143
+ Module *Importing = Worklist.pop_back_val ();
144
+
145
+ if (VisibleModules.isVisible (Importing))
146
+ continue ;
147
+
148
+ // FIXME: The ImportLoc here is not meaningful. It may be problematic if we
149
+ // use the sourcelocation loaded from the visible modules.
150
+ VisibleModules.setVisible (Importing, ImportLoc);
151
+
152
+ if (isImportingModuleUnitFromSameModule (Importing, CurrentModule,
153
+ FoundPrimaryModuleInterface))
154
+ for (Module *TransImported : Importing->Imports )
155
+ if (!VisibleModules.isVisible (TransImported))
156
+ Worklist.push_back (TransImported);
157
+ }
158
+ }
159
+
76
160
Sema::DeclGroupPtrTy
77
161
Sema::ActOnGlobalModuleFragmentDecl (SourceLocation ModuleLoc) {
78
162
// We start in the global module;
@@ -396,8 +480,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
396
480
// and return the import decl to be added to the current TU.
397
481
if (Interface) {
398
482
399
- VisibleModules. setVisible ( Interface, ModuleLoc);
400
- VisibleModules. makeTransitiveImportsVisible (Interface, ModuleLoc );
483
+ makeTransitiveImportsVisible (VisibleModules, Interface, Mod, ModuleLoc,
484
+ /* IsImportingPrimaryModuleInterface= */ true );
401
485
402
486
// Make the import decl for the interface in the impl module.
403
487
ImportDecl *Import = ImportDecl::Create (Context, CurContext, ModuleLoc,
@@ -554,7 +638,11 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
554
638
if (Mod->isHeaderUnit ())
555
639
Diag (ImportLoc, diag::warn_experimental_header_unit);
556
640
557
- VisibleModules.setVisible (Mod, ImportLoc);
641
+ if (Mod->isNamedModule ())
642
+ makeTransitiveImportsVisible (VisibleModules, Mod, getCurrentModule (),
643
+ ImportLoc);
644
+ else
645
+ VisibleModules.setVisible (Mod, ImportLoc);
558
646
559
647
checkModuleImportContext (*this , Mod, ImportLoc, CurContext);
560
648
0 commit comments