@@ -328,6 +328,9 @@ class ABIDependencyEvaluator {
328
328
329
329
llvm::DenseSet<ModuleDecl *> visited;
330
330
331
+ // / Cache to avoid recomputing public imports of Swift modules repeatedly.
332
+ llvm::DenseMap<ModuleDecl *, bool > isOverlayCache;
333
+
331
334
// / Helper function to handle invariant violations as crashes in debug mode.
332
335
void crashOnInvariantViolation (
333
336
llvm::function_ref<void (llvm::raw_string_ostream &)> f) const ;
@@ -342,6 +345,31 @@ class ABIDependencyEvaluator {
342
345
void reexposeImportedABI (ModuleDecl *module , ModuleDecl *importedModule,
343
346
bool includeImportedModule = true );
344
347
348
+ // / Check if a Swift module is an overlay for some Clang module.
349
+ // /
350
+ // / FIXME: Delete this hack once SR-13363 is fixed and ModuleDecl has the
351
+ // / right API which we can use directly.
352
+ bool isOverlayOfClangModule (ModuleDecl *swiftModule);
353
+
354
+ // / Check for cases where we have a fake cycle through an overlay.
355
+ // /
356
+ // / \code
357
+ // / Actual stack:
358
+ // / sandwichedModule -> Overlay (Swift) -> ... -> sandwichedModule
359
+ // / ^^--- wrong!
360
+ // / Ideal stack:
361
+ // / sandwichedModule -> Underlying (Clang)
362
+ // / \endcode
363
+ // /
364
+ // / This happens when we have a dependency like:
365
+ // / \code
366
+ // / Overlay (Swift) -> sandwichedModule -> Underlying (Clang)
367
+ // / \endcode
368
+ // /
369
+ // / We check this lazily because eagerly detecting if the dependency on an
370
+ // / overlay is correct or not is difficult.
371
+ bool isFakeCycleThroughOverlay (ModuleDecl **sandwichedModuleIter);
372
+
345
373
// / Recursive step in computing ABI dependencies.
346
374
// /
347
375
// / Use this method instead of using the \c forClangModule/\c forSwiftModule
@@ -453,9 +481,47 @@ void ABIDependencyEvaluator::reexposeImportedABI(
453
481
addToABIExportMap (module , reexportedModule);
454
482
}
455
483
484
+ bool ABIDependencyEvaluator::isOverlayOfClangModule (ModuleDecl *swiftModule) {
485
+ assert (!swiftModule->isNonSwiftModule ());
486
+
487
+ auto cacheEntry = isOverlayCache.find (swiftModule);
488
+ if (cacheEntry != isOverlayCache.end ())
489
+ return cacheEntry->second ;
490
+
491
+ llvm::SmallPtrSet<ModuleDecl *, 8 > importList;
492
+ ::getImmediateImports (swiftModule, importList,
493
+ {ModuleDecl::ImportFilterKind::Public});
494
+ bool isOverlay =
495
+ llvm::any_of (importList, [&](ModuleDecl *importedModule) -> bool {
496
+ return isClangOverlayOf (swiftModule, importedModule);
497
+ });
498
+ isOverlayCache[swiftModule] = isOverlay;
499
+ return isOverlay;
500
+ }
501
+
502
+ bool ABIDependencyEvaluator::isFakeCycleThroughOverlay (
503
+ ModuleDecl **sandwichModuleIter) {
504
+ assert (sandwichModuleIter >= searchStack.begin ()
505
+ && sandwichModuleIter < searchStack.end ()
506
+ && " sandwichModuleIter points to an element in searchStack" );
507
+ // The sandwichedModule must be a Clang module.
508
+ if (!(*sandwichModuleIter)->isNonSwiftModule ())
509
+ return false ;
510
+ auto nextModuleIter = sandwichModuleIter + 1 ;
511
+ if (nextModuleIter == searchStack.end ())
512
+ return false ;
513
+ // The next module must be a Swift overlay for a Clang module
514
+ if ((*nextModuleIter)->isNonSwiftModule ())
515
+ return false ;
516
+ return isOverlayOfClangModule (*nextModuleIter);
517
+ }
518
+
456
519
void ABIDependencyEvaluator::computeABIDependenciesForModule (
457
520
ModuleDecl *module ) {
458
- if (llvm::find (searchStack, module ) != searchStack.end ()) {
521
+ auto moduleIter = llvm::find (searchStack, module );
522
+ if (moduleIter != searchStack.end ()) {
523
+ if (isFakeCycleThroughOverlay (moduleIter))
524
+ return ;
459
525
crashOnInvariantViolation ([&](llvm::raw_string_ostream &os) {
460
526
os << " unexpected cycle in import graph!\n " ;
461
527
for (auto m: searchStack) {
@@ -510,6 +576,10 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule(
510
576
// C' imports S. This creates a cycle: S -> C' -> ... -> S.
511
577
// In practice, this case is hit for
512
578
// Darwin (Swift) -> SwiftOverlayShims (Clang) -> Darwin (Swift).
579
+ // We may also hit this in a slightly different direction, in case
580
+ // the module directly imports SwiftOverlayShims:
581
+ // SwiftOverlayShims -> Darwin (Swift) -> SwiftOverlayShims
582
+ // The latter is handled later by isFakeCycleThroughOverlay.
513
583
// 3. [NOTE: Intra-module-leafwards-traversal]
514
584
// Cycles within the same top-level module.
515
585
// These don't matter for us, since we only care about the dependency
@@ -519,9 +589,8 @@ void ABIDependencyEvaluator::computeABIDependenciesForClangModule(
519
589
if (import ->isStdlibModule ()) {
520
590
continue ;
521
591
}
522
- if (!import ->isNonSwiftModule ()
523
- && import ->findUnderlyingClangModule () != nullptr
524
- && llvm::find (searchStack, import ) != searchStack.end ()) {
592
+ if (!import ->isNonSwiftModule () && isOverlayOfClangModule (import ) &&
593
+ llvm::find (searchStack, import ) != searchStack.end ()) {
525
594
continue ;
526
595
}
527
596
if (import ->isNonSwiftModule ()
0 commit comments