Skip to content

Commit 121fa9a

Browse files
committed
Ignore transitive ObjC imports when cross-importing
This behavior change reduces the chance of unexpected and unwanted cross-imports being performed. Fixes rdar://problem/60554019.
1 parent 1d423e4 commit 121fa9a

File tree

12 files changed

+72
-23
lines changed

12 files changed

+72
-23
lines changed

include/swift/AST/ClangModuleLoader.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ class ClangModuleLoader : public ModuleLoader {
128128

129129
/// Retrieves the Swift wrapper for the given Clang module, creating
130130
/// it if necessary.
131-
virtual ModuleDecl *getWrapperForModule(const clang::Module *mod) const = 0;
131+
virtual ModuleDecl *
132+
getWrapperForModule(const clang::Module *mod,
133+
bool returnOverlayIfPossible = false) const = 0;
132134

133135
/// Adds a new search path to the Clang CompilerInstance, as if specified with
134136
/// -I or -F.

include/swift/AST/Module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ class ModuleDecl : public DeclContext, public TypeDecl {
448448
/// Retrieve the top-level module. If this module is already top-level, this
449449
/// returns itself. If this is a submodule such as \c Foo.Bar.Baz, this
450450
/// returns the module \c Foo.
451-
ModuleDecl *getTopLevelModule();
451+
ModuleDecl *getTopLevelModule(bool overlay = false);
452452

453453
bool isResilient() const {
454454
return getResilienceStrategy() != ResilienceStrategy::Default;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,9 @@ class ClangImporter final : public ClangModuleLoader {
330330

331331
/// Retrieves the Swift wrapper for the given Clang module, creating
332332
/// it if necessary.
333-
ModuleDecl *getWrapperForModule(const clang::Module *mod) const override;
333+
ModuleDecl *
334+
getWrapperForModule(const clang::Module *mod,
335+
bool returnOverlayIfPossible = false) const override;
334336

335337
std::string getBridgingHeaderContents(StringRef headerPath, off_t &fileSize,
336338
time_t &fileModTime);

lib/AST/Module.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,15 +508,16 @@ SourceLookupCache &ModuleDecl::getSourceLookupCache() const {
508508
return *Cache;
509509
}
510510

511-
ModuleDecl *ModuleDecl::getTopLevelModule() {
511+
ModuleDecl *ModuleDecl::getTopLevelModule(bool overlay) {
512512
// If this is a Clang module, ask the Clang importer for the top-level module.
513513
// We need to check isNonSwiftModule() to ensure we don't look through
514514
// overlays.
515515
if (isNonSwiftModule()) {
516516
if (auto *underlying = findUnderlyingClangModule()) {
517517
auto &ctx = getASTContext();
518518
auto *clangLoader = ctx.getClangModuleLoader();
519-
return clangLoader->getWrapperForModule(underlying->getTopLevelModule());
519+
return clangLoader->getWrapperForModule(underlying->getTopLevelModule(),
520+
overlay);
520521
}
521522
}
522523
// Swift modules don't currently support submodules.

lib/ClangImporter/ClangImporter.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,8 +1860,13 @@ ModuleDecl *ClangImporter::getImportedHeaderModule() const {
18601860
return Impl.ImportedHeaderUnit->getParentModule();
18611861
}
18621862

1863-
ModuleDecl *ClangImporter::getWrapperForModule(const clang::Module *mod) const {
1864-
return Impl.getWrapperForModule(mod)->getParentModule();
1863+
ModuleDecl *
1864+
ClangImporter::getWrapperForModule(const clang::Module *mod,
1865+
bool returnOverlayIfPossible) const {
1866+
auto clangUnit = Impl.getWrapperForModule(mod);
1867+
if (returnOverlayIfPossible && clangUnit->getOverlayModule())
1868+
return clangUnit->getOverlayModule();
1869+
return clangUnit->getParentModule();
18651870
}
18661871

18671872
PlatformAvailability::PlatformAvailability(LangOptions &langOpts)

lib/Sema/ImportResolution.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,13 @@ class ImportResolver final : public DeclVisitor<ImportResolver> {
172172
/// The list of fully bound imports.
173173
SmallVector<ImportedModuleDesc, 16> boundImports;
174174

175-
/// All imported modules, including by re-exports, and including submodules.
176-
llvm::DenseSet<ImportedModuleDesc> visibleModules;
177-
178-
/// \c visibleModules but without the submodules.
175+
/// All imported modules which should be considered when cross-importing.
176+
/// This is basically the transitive import graph, but with only top-level
177+
/// modules and without reexports from Objective-C modules.
179178
///
180179
/// We use a \c SmallSetVector here because this doubles as the worklist for
181180
/// cross-importing, so we want to keep it in order; this is feasible
182-
/// because this set is usually fairly small, while \c visibleModules is
183-
/// often enormous.
181+
/// because this set is usually fairly small.
184182
SmallSetVector<ImportedModuleDesc, 64> crossImportableModules;
185183

186184
/// The subset of \c crossImportableModules which may declare cross-imports.
@@ -223,7 +221,7 @@ class ImportResolver final : public DeclVisitor<ImportResolver> {
223221

224222
/// Adds \p desc and everything it re-exports to \c visibleModules using
225223
/// the settings from \c desc.
226-
void addVisibleModules(ImportedModuleDesc desc);
224+
void addCrossImportableModules(ImportedModuleDesc desc);
227225

228226
/// * If \p I is a cross-import overlay, registers \p M as overlaying
229227
/// \p I.underlyingModule in \c SF.
@@ -341,7 +339,7 @@ void ImportResolver::bindImport(UnboundImport &&I) {
341339

342340
void ImportResolver::addImport(const UnboundImport &I, ModuleDecl *M) {
343341
auto importDesc = I.makeDesc(M);
344-
addVisibleModules(importDesc);
342+
addCrossImportableModules(importDesc);
345343
boundImports.push_back(importDesc);
346344
}
347345

@@ -931,7 +929,7 @@ static bool isSubmodule(ModuleDecl* M) {
931929
return clangMod && clangMod->Parent;
932930
}
933931

934-
void ImportResolver::addVisibleModules(ImportedModuleDesc importDesc) {
932+
void ImportResolver::addCrossImportableModules(ImportedModuleDesc importDesc) {
935933
// FIXME: namelookup::getAllImports() doesn't quite do what we need (mainly
936934
// w.r.t. scoped imports), but it seems like we could extend it to do so, and
937935
// then eliminate most of this.
@@ -948,19 +946,34 @@ void ImportResolver::addVisibleModules(ImportedModuleDesc importDesc) {
948946
nextImport.first))
949947
continue;
950948

949+
// If we are importing a submodule, treat it as though we imported its
950+
// top-level module (or rather, the top-level module's clang overlay if it
951+
// has one).
952+
if (isSubmodule(nextImport.second)) {
953+
nextImport.second =
954+
nextImport.second->getTopLevelModule(/*overlay=*/true);
955+
956+
// If the rewritten import is now for our own parent module, this was an
957+
// import of our own clang submodule in a mixed-language module. We don't
958+
// want to process our own cross-imports.
959+
if (nextImport.second == SF.getParentModule())
960+
continue;
961+
}
962+
951963
// Drop this module into the ImportDesc so we treat it as imported with the
952964
// same options and scope as `I`.
953965
importDesc.module.second = nextImport.second;
954966

955-
// If we've already imported it, we've also already imported its
956-
// imports.
957-
if (!visibleModules.insert(importDesc).second)
967+
// Add it to the list of cross-importable modules. If it's already there,
968+
// we've already done the rest of the work of this loop iteration and can
969+
// skip it.
970+
if (!crossImportableModules.insert(importDesc))
958971
continue;
959972

960-
// We don't cross-import submodules, so we shouldn't add them to the
961-
// visibility set. (However, we do consider their reexports.)
962-
if(!isSubmodule(importDesc.module.second))
963-
crossImportableModules.insert(importDesc);
973+
// We don't consider the re-exports of ObjC modules because ObjC re-exports
974+
// everything, so there isn't enough signal there to work from.
975+
if (nextImport.second->isNonSwiftModule())
976+
continue;
964977

965978
// Add the module's re-exports to worklist.
966979
nextImport.second->getImportedModules(importsWorklist,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void fromCoreMI6();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
%YAML 1.2
2+
---
3+
version: 1
4+
modules:
5+
- name: _NeverImportedOverlay

test/CrossImport/Inputs/lib-templates/include/module.modulemap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ module ClangLibrary {
44
header "clang_library_submodule.h"
55
}
66
}
7+
module core_mi6 {
8+
header "core_mi6.h"
9+
export *
10+
}
11+
module UniversalExports {
12+
header "universal_exports.h"
13+
export *
14+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#import <core_mi6.h>
2+
void fromUniversalExportsClang();

test/CrossImport/Inputs/lib-templates/lib/swift/UniversalExports.swiftinterface

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// swift-module-flags: -swift-version 5 -enable-library-evolution -module-name UniversalExports
33

44
import Swift
5+
6+
// This is also a clang overlay:
7+
@_exported import UniversalExports
8+
59
@_exported import AlwaysImported
610
import NeverImported
711
import MI6 // @_exported imports NeverImported

test/CrossImport/transitive.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ import UniversalExports
1414
import ThinLibrary
1515
#endif
1616

17+
// We should have loaded the underlying clang module.
18+
fromUniversalExportsClang() // no-error
19+
20+
// We should have loaded core_mi6 too.
21+
fromCoreMI6() // no-error
22+
1723
// We should have loaded _AlwaysImportedOverlay.
1824
fromAlwaysImportedOverlay() // no-error
1925

0 commit comments

Comments
 (0)