Skip to content

Commit 5fa31c6

Browse files
authored
Merge pull request #62029 from xymus/reexport-spi
[Sema] @_exported imports reexport @_spi decls as they reexport APIs
2 parents 37bca0d + c0abde0 commit 5fa31c6

File tree

5 files changed

+164
-22
lines changed

5 files changed

+164
-22
lines changed

lib/AST/Module.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,11 +2849,12 @@ canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const {
28492849
void SourceFile::lookupImportedSPIGroups(
28502850
const ModuleDecl *importedModule,
28512851
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {
2852+
auto &imports = getASTContext().getImportCache();
28522853
for (auto &import : *Imports) {
28532854
if (import.options.contains(ImportFlags::SPIAccessControl) &&
2854-
importedModule == import.module.importedModule) {
2855-
auto importedSpis = import.spiGroups;
2856-
spiGroups.insert(importedSpis.begin(), importedSpis.end());
2855+
(importedModule == import.module.importedModule ||
2856+
imports.isImportedBy(importedModule, import.module.importedModule))) {
2857+
spiGroups.insert(import.spiGroups.begin(), import.spiGroups.end());
28572858
}
28582859
}
28592860
}

lib/Serialization/ModuleFile.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -889,18 +889,6 @@ void ModuleFile::lookupObjCMethods(
889889
}
890890
}
891891

892-
void ModuleFile::lookupImportedSPIGroups(
893-
const ModuleDecl *importedModule,
894-
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {
895-
for (auto &dep : Dependencies) {
896-
auto depSpis = dep.spiGroups;
897-
if (dep.Import.hasValue() && dep.Import->importedModule == importedModule &&
898-
!depSpis.empty()) {
899-
spiGroups.insert(depSpis.begin(), depSpis.end());
900-
}
901-
}
902-
}
903-
904892
void
905893
ModuleFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {
906894
for (const auto &lib : Core->LinkLibraries)

lib/Serialization/ModuleFile.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,12 +670,6 @@ class ModuleFile
670670
ObjCSelector selector,
671671
SmallVectorImpl<AbstractFunctionDecl *> &results);
672672

673-
/// Find all SPI names imported from \p importedModule by this module,
674-
/// collecting the identifiers in \p spiGroups.
675-
void lookupImportedSPIGroups(
676-
const ModuleDecl *importedModule,
677-
llvm::SmallSetVector<Identifier, 4> &spiGroups) const;
678-
679673
/// Reports all link-time dependencies.
680674
void collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const;
681675

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "ModuleFileSharedCore.h"
1616
#include "swift/AST/ASTContext.h"
1717
#include "swift/AST/DiagnosticsSema.h"
18+
#include "swift/AST/ImportCache.h"
1819
#include "swift/AST/ModuleDependencies.h"
1920
#include "swift/Basic/Defer.h"
2021
#include "swift/Basic/FileTypes.h"
@@ -1486,7 +1487,17 @@ SerializedASTFile::loadFingerprint(const IterableDeclContext *IDC) const {
14861487
void SerializedASTFile::lookupImportedSPIGroups(
14871488
const ModuleDecl *importedModule,
14881489
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {
1489-
File.lookupImportedSPIGroups(importedModule, spiGroups);
1490+
auto M = getParentModule();
1491+
auto &imports = M->getASTContext().getImportCache();
1492+
for (auto &dep : File.Dependencies) {
1493+
if (!dep.Import.hasValue())
1494+
continue;
1495+
1496+
if (dep.Import->importedModule == importedModule ||
1497+
imports.isImportedBy(importedModule, dep.Import->importedModule)) {
1498+
spiGroups.insert(dep.spiGroups.begin(), dep.spiGroups.end());
1499+
}
1500+
}
14901501
}
14911502

14921503
Optional<CommentInfo>

test/SPI/reexported-spi-groups.swift

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
/// Build lib defining SPIs
5+
// RUN: %target-swift-frontend -emit-module %t/Exported.swift \
6+
// RUN: -module-name Exported -swift-version 5 \
7+
// RUN: -enable-library-evolution \
8+
// RUN: -emit-module-path %t/Exported.swiftmodule \
9+
// RUN: -emit-module-interface-path %t/Exported.swiftinterface \
10+
// 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
13+
14+
/// Build lib reexporting SPIs
15+
// RUN: %target-swift-frontend -emit-module %t/Exporter.swift \
16+
// RUN: -module-name Exporter -swift-version 5 -I %t \
17+
// RUN: -enable-library-evolution \
18+
// RUN: -emit-module-path %t/Exporter.swiftmodule \
19+
// RUN: -emit-module-interface-path %t/Exporter.swiftinterface \
20+
// RUN: -emit-private-module-interface-path %t/Exporter.private.swiftinterface
21+
// RUN: %target-swift-typecheck-module-from-interface(%t/Exporter.swiftinterface) -I %t
22+
// RUN: %target-swift-typecheck-module-from-interface(%t/Exporter.private.swiftinterface) -module-name Exporter -I %t
23+
24+
/// Build lib not reexporting SPIs (a normal import)
25+
// RUN: %target-swift-frontend -emit-module %t/NonExporter.swift \
26+
// RUN: -module-name NonExporter -swift-version 5 -I %t \
27+
// RUN: -enable-library-evolution \
28+
// RUN: -emit-module-path %t/NonExporter.swiftmodule \
29+
// RUN: -emit-module-interface-path %t/NonExporter.swiftinterface \
30+
// RUN: -emit-private-module-interface-path %t/NonExporter.private.swiftinterface
31+
// RUN: %target-swift-typecheck-module-from-interface(%t/NonExporter.swiftinterface) -I %t
32+
// RUN: %target-swift-typecheck-module-from-interface(%t/NonExporter.private.swiftinterface) -module-name NonExporter -I %t
33+
34+
/// Build client of transitive SPIs and its swiftinterfaces
35+
// RUN: %target-swift-frontend -emit-module %t/ClientLib.swift \
36+
// RUN: -module-name ClientLib -swift-version 5 -I %t \
37+
// RUN: -enable-library-evolution \
38+
// RUN: -emit-module-path %t/ClientLib.swiftmodule \
39+
// RUN: -emit-module-interface-path %t/ClientLib.swiftinterface \
40+
// RUN: -emit-private-module-interface-path %t/ClientLib.private.swiftinterface
41+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.swiftinterface) -I %t
42+
// RUN: %target-swift-typecheck-module-from-interface(%t/ClientLib.private.swiftinterface) -module-name ClientLib -I %t
43+
44+
/// Test diagnostics of a multifile client
45+
// RUN: %target-swift-frontend -typecheck \
46+
// RUN: %t/Client_FileA.swift %t/Client_FileB.swift\
47+
// RUN: -swift-version 5 -I %t -verify
48+
49+
/// Test that SPIs don't leak when not reexported
50+
// RUN: %target-swift-frontend -typecheck \
51+
// RUN: %t/NonExporterClient.swift \
52+
// RUN: -swift-version 5 -I %t -verify
53+
54+
/// Test diagnostics against private swiftinterfaces
55+
// RUN: rm %t/Exported.swiftmodule %t/Exporter.swiftmodule
56+
// RUN: %target-swift-frontend -typecheck \
57+
// RUN: %t/Client_FileA.swift %t/Client_FileB.swift\
58+
// RUN: -swift-version 5 -I %t -verify
59+
60+
/// Test diagnostics against public swiftinterfaces
61+
// RUN: rm %t/Exported.private.swiftinterface %t/Exporter.private.swiftinterface
62+
// RUN: %target-swift-frontend -typecheck \
63+
// RUN: %t/PublicClient.swift \
64+
// RUN: -swift-version 5 -I %t -verify
65+
66+
67+
//--- Exported.swift
68+
69+
public func exportedPublicFunc() {}
70+
71+
@_spi(X) public func exportedSpiFunc() {}
72+
73+
@_spi(X) public struct ExportedSpiType {}
74+
75+
//--- Exporter.swift
76+
77+
@_exported import Exported
78+
79+
@_spi(X) public func exporterSpiFunc() {}
80+
81+
//--- NonExporter.swift
82+
83+
@_spi(X) import Exported
84+
85+
@_spi(X) public func exporterSpiFunc() {}
86+
87+
//--- ClientLib.swift
88+
89+
@_spi(X) import Exporter
90+
91+
public func clientA() {
92+
exportedPublicFunc()
93+
exportedSpiFunc()
94+
exporterSpiFunc()
95+
}
96+
97+
@_spi(X) public func spiUseExportedSpiType(_ a: ExportedSpiType) {}
98+
99+
//--- Client_FileA.swift
100+
101+
@_spi(X) import Exporter
102+
103+
public func clientA() {
104+
exportedPublicFunc()
105+
exportedSpiFunc()
106+
exporterSpiFunc()
107+
}
108+
109+
@inlinable
110+
public func inlinableClient() {
111+
exportedPublicFunc()
112+
exportedSpiFunc() // expected-error {{global function 'exportedSpiFunc()' cannot be used in an '@inlinable' function because it is an SPI imported from 'Exported'}}
113+
exporterSpiFunc() // expected-error {{global function 'exporterSpiFunc()' cannot be used in an '@inlinable' function because it is an SPI imported from 'Exporter'}}
114+
}
115+
116+
@_spi(X) public func spiUseExportedSpiType(_ a: ExportedSpiType) {}
117+
118+
public func publicUseExportedSpiType(_ a: ExportedSpiType) {} // expected-error {{cannot use struct 'ExportedSpiType' here; it is an SPI imported from 'Exported'}}
119+
120+
//--- Client_FileB.swift
121+
122+
import Exporter
123+
124+
public func clientB() {
125+
exportedPublicFunc()
126+
exportedSpiFunc() // expected-error {{cannot find 'exportedSpiFunc' in scope}}
127+
exporterSpiFunc() // expected-error {{cannot find 'exporterSpiFunc' in scope}}
128+
}
129+
130+
//--- NonExporterClient.swift
131+
132+
@_spi(X) import NonExporter
133+
134+
public func client() {
135+
exportedPublicFunc() // expected-error {{cannot find 'exportedPublicFunc' in scope}}
136+
exportedSpiFunc() // expected-error {{cannot find 'exportedSpiFunc' in scope}}
137+
exporterSpiFunc()
138+
}
139+
140+
//--- PublicClient.swift
141+
142+
@_spi(X) import Exporter // expected-warning {{'@_spi' import of 'Exporter' will not include any SPI symbols}}
143+
144+
public func client() {
145+
exportedPublicFunc()
146+
exportedSpiFunc() // expected-error {{cannot find 'exportedSpiFunc' in scope}}
147+
exporterSpiFunc() // expected-error {{cannot find 'exporterSpiFunc' in scope}}
148+
}

0 commit comments

Comments
 (0)