Skip to content

Commit a325f81

Browse files
committed
[AST] Rewrite collectExportedImports() to be non-recursive.
The issue with recursion here is that if there are enough modules involved, this function will blow the process stack, particularly in the case where the `FileUnit`s are not `SourceFile`s, since in that instance a `SmallVector` gets allocated on the stack for each level of the recursion. rdar://130527640
1 parent 4058a08 commit a325f81

File tree

1 file changed

+27
-22
lines changed

1 file changed

+27
-22
lines changed

lib/AST/Module.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,31 +1534,36 @@ void ModuleDecl::ImportCollector::collect(
15341534
}
15351535

15361536
static void
1537-
collectExportedImports(const ModuleDecl *module,
1537+
collectExportedImports(const ModuleDecl *topLevelModule,
15381538
ModuleDecl::ImportCollector &importCollector) {
1539-
for (const FileUnit *file : module->getFiles()) {
1540-
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
1541-
if (source->hasImports()) {
1542-
for (const auto &import : source->getImports()) {
1543-
if (import.options.contains(ImportFlags::Exported) &&
1544-
import.docVisibility.value_or(AccessLevel::Public) >=
1545-
importCollector.minimumDocVisibility) {
1546-
importCollector.collect(import.module);
1547-
collectExportedImports(import.module.importedModule,
1548-
importCollector);
1539+
SmallVector<const ModuleDecl *> stack;
1540+
stack.push_back(topLevelModule);
1541+
while (!stack.empty()) {
1542+
const ModuleDecl *module = stack.pop_back_val();
1543+
1544+
for (const FileUnit *file : module->getFiles()) {
1545+
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
1546+
if (source->hasImports()) {
1547+
for (const auto &import : source->getImports()) {
1548+
if (import.options.contains(ImportFlags::Exported) &&
1549+
import.docVisibility.value_or(AccessLevel::Public) >=
1550+
importCollector.minimumDocVisibility) {
1551+
importCollector.collect(import.module);
1552+
stack.push_back(import.module.importedModule);
1553+
}
15491554
}
15501555
}
1551-
}
1552-
} else {
1553-
SmallVector<ImportedModule, 8> exportedImports;
1554-
file->getImportedModules(exportedImports,
1555-
ModuleDecl::ImportFilterKind::Exported);
1556-
for (const auto &im : exportedImports) {
1557-
// Skip collecting the underlying clang module as we already have the relevant import.
1558-
if (module->isClangOverlayOf(im.importedModule))
1559-
continue;
1560-
importCollector.collect(im);
1561-
collectExportedImports(im.importedModule, importCollector);
1556+
} else {
1557+
SmallVector<ImportedModule, 8> exportedImports;
1558+
file->getImportedModules(exportedImports,
1559+
ModuleDecl::ImportFilterKind::Exported);
1560+
for (const auto &im : exportedImports) {
1561+
// Skip collecting the underlying clang module as we already have the relevant import.
1562+
if (module->isClangOverlayOf(im.importedModule))
1563+
continue;
1564+
importCollector.collect(im);
1565+
stack.push_back(im.importedModule);
1566+
}
15621567
}
15631568
}
15641569
}

0 commit comments

Comments
 (0)