Skip to content

Commit 552d3a4

Browse files
committed
[Sema] Restrict reexported SPIs to modules with an export_as relationship
@_exported exports SPIs only when the exported module defines export_as pointing to the exporter module. Other reexports do not reexport SPIs. This is to prevent SPI reexporting to get out of hands with the wide reexports of the Objective-C world. rdar://102335473
1 parent e52fbb8 commit 552d3a4

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

lib/AST/Module.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2861,7 +2861,8 @@ void SourceFile::lookupImportedSPIGroups(
28612861
for (auto &import : *Imports) {
28622862
if (import.options.contains(ImportFlags::SPIAccessControl) &&
28632863
(importedModule == import.module.importedModule ||
2864-
imports.isImportedBy(importedModule, import.module.importedModule))) {
2864+
(imports.isImportedBy(importedModule, import.module.importedModule) &&
2865+
importedModule->isExportedAs(import.module.importedModule)))) {
28652866
spiGroups.insert(import.spiGroups.begin(), import.spiGroups.end());
28662867
}
28672868
}

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,8 @@ void SerializedASTFile::lookupImportedSPIGroups(
14941494
continue;
14951495

14961496
if (dep.Import->importedModule == importedModule ||
1497-
imports.isImportedBy(importedModule, dep.Import->importedModule)) {
1497+
(imports.isImportedBy(importedModule, dep.Import->importedModule) &&
1498+
importedModule->isExportedAs(dep.Import->importedModule))) {
14981499
spiGroups.insert(dep.spiGroups.begin(), dep.spiGroups.end());
14991500
}
15001501
}

test/SPI/reexported-spi-groups.swift

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
/// Build lib defining SPIs
55
// RUN: %target-swift-frontend -emit-module %t/Exported.swift \
6-
// RUN: -module-name Exported -swift-version 5 \
6+
// RUN: -module-name Exported -swift-version 5 -I %t \
77
// RUN: -enable-library-evolution \
88
// RUN: -emit-module-path %t/Exported.swiftmodule \
99
// RUN: -emit-module-interface-path %t/Exported.swiftinterface \
1010
// RUN: -emit-private-module-interface-path %t/Exported.private.swiftinterface
11-
// RUN: %target-swift-typecheck-module-from-interface(%t/Exported.swiftinterface)
12-
// RUN: %target-swift-typecheck-module-from-interface(%t/Exported.private.swiftinterface) -module-name Exported
11+
// RUN: %target-swift-typecheck-module-from-interface(%t/Exported.swiftinterface) -I %t
12+
// RUN: %target-swift-typecheck-module-from-interface(%t/Exported.private.swiftinterface) -module-name Exported -I %t
1313

1414
/// Build lib reexporting SPIs
1515
// RUN: %target-swift-frontend -emit-module %t/Exporter.swift \
@@ -21,6 +21,15 @@
2121
// RUN: %target-swift-typecheck-module-from-interface(%t/Exporter.swiftinterface) -I %t
2222
// RUN: %target-swift-typecheck-module-from-interface(%t/Exporter.private.swiftinterface) -module-name Exporter -I %t
2323

24+
// RUN: %target-swift-frontend -emit-module %t/NonExportedAs.swift \
25+
// RUN: -module-name NonExportedAs -swift-version 5 -I %t \
26+
// RUN: -enable-library-evolution \
27+
// RUN: -emit-module-path %t/NonExportedAs.swiftmodule \
28+
// RUN: -emit-module-interface-path %t/NonExportedAs.swiftinterface \
29+
// RUN: -emit-private-module-interface-path %t/NonExportedAs.private.swiftinterface
30+
// RUN: %target-swift-typecheck-module-from-interface(%t/NonExportedAs.swiftinterface) -I %t
31+
// RUN: %target-swift-typecheck-module-from-interface(%t/NonExportedAs.private.swiftinterface) -module-name NonExportedAs -I %t
32+
2433
/// Build lib not reexporting SPIs (a normal import)
2534
// RUN: %target-swift-frontend -emit-module %t/NonExporter.swift \
2635
// RUN: -module-name NonExporter -swift-version 5 -I %t \
@@ -46,6 +55,11 @@
4655
// RUN: %t/Client_FileA.swift %t/Client_FileB.swift\
4756
// RUN: -swift-version 5 -I %t -verify
4857

58+
/// Test that SPIs aren't avaible from a reexport without export_as
59+
// RUN: %target-swift-frontend -typecheck \
60+
// RUN: %t/NonExportedAsClient.swift \
61+
// RUN: -swift-version 5 -I %t -verify
62+
4963
/// Test that SPIs don't leak when not reexported
5064
// RUN: %target-swift-frontend -typecheck \
5165
// RUN: %t/NonExporterClient.swift \
@@ -63,9 +77,15 @@
6377
// RUN: %t/PublicClient.swift \
6478
// RUN: -swift-version 5 -I %t -verify
6579

80+
//--- module.modulemap
81+
module Exported {
82+
export_as Exporter
83+
}
6684

6785
//--- Exported.swift
6886

87+
@_exported import Exported
88+
6989
public func exportedPublicFunc() {}
7090

7191
@_spi(X) public func exportedSpiFunc() {}
@@ -78,6 +98,12 @@ public func exportedPublicFunc() {}
7898

7999
@_spi(X) public func exporterSpiFunc() {}
80100

101+
//--- NonExportedAs.swift
102+
103+
@_exported import Exported
104+
105+
@_spi(X) public func exporterSpiFunc() {}
106+
81107
//--- NonExporter.swift
82108

83109
@_spi(X) import Exported
@@ -127,6 +153,16 @@ public func clientB() {
127153
exporterSpiFunc() // expected-error {{cannot find 'exporterSpiFunc' in scope}}
128154
}
129155

156+
//--- NonExportedAsClient.swift
157+
158+
@_spi(X) import NonExportedAs
159+
160+
public func client() {
161+
exportedPublicFunc()
162+
exportedSpiFunc() // expected-error {{cannot find 'exportedSpiFunc' in scope}}
163+
exporterSpiFunc()
164+
}
165+
130166
//--- NonExporterClient.swift
131167

132168
@_spi(X) import NonExporter

0 commit comments

Comments
 (0)