Skip to content

Commit f7414ed

Browse files
authored
Merge pull request #62102 from xymus/spi-reexported-export-as
[Sema] Restrict reexported SPIs to modules with an `export_as` relationship
2 parents 5e208ff + 552d3a4 commit f7414ed

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

include/swift/AST/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,10 @@ class ModuleDecl
877877
/// Returns the associated clang module if one exists.
878878
const clang::Module *findUnderlyingClangModule() const;
879879

880+
/// Does this module or the underlying clang module defines export_as with
881+
/// a value corresponding to the \p other module?
882+
bool isExportedAs(const ModuleDecl *other) const;
883+
880884
/// Returns a generator with the components of this module's full,
881885
/// hierarchical name.
882886
///

lib/AST/Module.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2175,6 +2175,14 @@ const clang::Module *ModuleDecl::findUnderlyingClangModule() const {
21752175
return nullptr;
21762176
}
21772177

2178+
bool ModuleDecl::isExportedAs(const ModuleDecl *other) const {
2179+
auto clangModule = findUnderlyingClangModule();
2180+
if (!clangModule)
2181+
return false;
2182+
2183+
return other->getRealName().str() == clangModule->ExportAsModule;
2184+
}
2185+
21782186
void ModuleDecl::collectBasicSourceFileInfo(
21792187
llvm::function_ref<void(const BasicSourceFileInfo &)> callback) const {
21802188
for (const FileUnit *fileUnit : getFiles()) {
@@ -2853,7 +2861,8 @@ void SourceFile::lookupImportedSPIGroups(
28532861
for (auto &import : *Imports) {
28542862
if (import.options.contains(ImportFlags::SPIAccessControl) &&
28552863
(importedModule == import.module.importedModule ||
2856-
imports.isImportedBy(importedModule, import.module.importedModule))) {
2864+
(imports.isImportedBy(importedModule, import.module.importedModule) &&
2865+
importedModule->isExportedAs(import.module.importedModule)))) {
28572866
spiGroups.insert(import.spiGroups.begin(), import.spiGroups.end());
28582867
}
28592868
}

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)