Skip to content

Commit dac3922

Browse files
committed
[Sema] Accept use of SPI in inlinable SPI declarations
rdar://63978500 rdar://63189125
1 parent 55e7050 commit dac3922

File tree

4 files changed

+65
-13
lines changed

4 files changed

+65
-13
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
7171
if (D->getDeclContext()->isLocalContext())
7272
return false;
7373

74-
// Public non-SPI declarations are OK.
74+
// Public declarations or SPI used from SPI are OK.
7575
if (D->getFormalAccessScope(/*useDC=*/nullptr,
7676
Kind.allowUsableFromInline).isPublic() &&
77-
!D->isSPI())
77+
!(D->isSPI() && !DC->getInnermostDeclarationDeclContext()->isSPI()))
7878
return false;
7979

8080
auto &Context = DC->getASTContext();
@@ -149,14 +149,15 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
149149

150150
static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
151151
const SourceFile &userSF,
152+
const DeclContext *userDC,
152153
FragileFunctionKind fragileKind) {
153154
assert(fragileKind.kind != FragileFunctionKind::None);
154155

155156
auto definingModule = D->getModuleContext();
156157

157-
bool isImplementationOnly =
158-
userSF.isImportedImplementationOnly(definingModule);
159-
if (!isImplementationOnly && !userSF.isImportedAsSPI(D))
158+
auto originKind = getDisallowedOriginKind(
159+
D, userSF, userDC->getInnermostDeclarationDeclContext());
160+
if (originKind == DisallowedOriginKind::None)
160161
return false;
161162

162163
// TODO: different diagnostics
@@ -165,7 +166,7 @@ static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
165166
D->getDescriptiveKind(), D->getName(),
166167
static_cast<unsigned>(fragileKind.kind),
167168
definingModule->getName(),
168-
static_cast<unsigned>(!isImplementationOnly));
169+
static_cast<unsigned>(originKind));
169170
return true;
170171
}
171172

@@ -234,7 +235,7 @@ TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
234235
return false;
235236

236237
const ValueDecl *D = declRef.getDecl();
237-
if (diagnoseDeclExportability(loc, D, *userSF, fragileKind))
238+
if (diagnoseDeclExportability(loc, D, *userSF, DC, fragileKind))
238239
return true;
239240
if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(),
240241
*userSF, DC)) {

test/SPI/local_spi_decls.swift

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@
77
// RUN: %target-typecheck-verify-swift -I %t -verify-ignore-unknown -swift-version 5
88

99
// SPI declarations
10-
@_spi(MySPI) public func spiFunc() {} // expected-note {{global function 'spiFunc()' is not '@usableFromInline' or public}}
10+
@_spi(MySPI) public func spiFunc() {} // expected-note 2 {{global function 'spiFunc()' is not '@usableFromInline' or public}}
1111
@_spi(+) public func invalidSPIName() {} // expected-error {{expected an SPI identifier as subject of the '@_spi' attribute}}
1212
@_spi(🤔) public func emojiNamedSPI() {}
1313
@_spi() public func emptyParensSPI() {} // expected-error {{expected an SPI identifier as subject of the '@_spi' attribute}}
1414
@_spi(set) public func keywordSPI() {} // expected-error {{expected an SPI identifier as subject of the '@_spi' attribute}}
1515

16-
@_spi(S) public class SPIClass {} // expected-note 3 {{type declared here}}
17-
// expected-note @-1 2 {{class 'SPIClass' is not '@usableFromInline' or public}}
16+
@_spi(S) public class SPIClass { // expected-note 5 {{type declared here}}
17+
// expected-note @-1 3 {{class 'SPIClass' is not '@usableFromInline' or public}}
18+
// expected-note @-2 {{class 'SPIClass' is not public}}
19+
public init() {}
20+
}
1821
class InternalClass {} // expected-note 2 {{type declared here}}
1922
private class PrivateClass {} // expected-note 2 {{type declared here}}
2023

@@ -31,13 +34,22 @@ func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' is '@_spi' a
3134
_ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
3235
}
3336

34-
@_spi(S) public struct SPIStruct {} // expected-note 2 {{struct 'SPIStruct' is not '@usableFromInline' or public}}
37+
@_spi(S) public struct SPIStruct { // expected-note 2 {{struct 'SPIStruct' is not '@usableFromInline' or public}}
38+
public init() {}
39+
}
3540

3641
@frozen public struct FrozenStruct {
3742
@_spi(S) public var spiInFrozen = SPIStruct() // expected-error {{struct 'SPIStruct' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
3843
// expected-error @-1 {{stored property 'spiInFrozen' cannot be declared '@_spi' in a '@frozen' struct}}
3944

40-
var asdf = SPIStruct() // expected-error {{struct 'SPIStruct' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
45+
var spiTypeInFrozen = SPIStruct() // expected-error {{struct 'SPIStruct' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
46+
private var spiTypeInFrozen1: SPIClass // expected-error {{cannot use class 'SPIClass' here; it is SPI}}
47+
}
48+
49+
@_spi(S)
50+
@frozen public struct SPIFrozenStruct {
51+
var spiTypeInFrozen = SPIStruct()
52+
private var spiTypeInFrozen1: SPIClass
4153
}
4254

4355
private protocol PrivateProtocol {} // expected-note {{type declared here}}
@@ -81,3 +93,22 @@ public struct NestedParent {
8193
public struct Nested { }
8294
let nested: Nested
8395
}
96+
97+
public func publicFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {} // expected-error {{cannot use class 'SPIClass' here; it is SPI}}
98+
// expected-error @-1 {{class 'SPIClass' is '@_spi' and cannot be referenced from a default argument value}}
99+
100+
@_spi(S)
101+
public func spiFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {}
102+
103+
@inlinable
104+
public func inlinablePublic() {
105+
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
106+
let _ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
107+
}
108+
109+
@_spi(S)
110+
@inlinable
111+
public func inlinableSPI() {
112+
spiFunc()
113+
let _ = SPIClass()
114+
}

test/SPI/private_swiftinterface.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ extension IOIPublicStruct : LocalPublicProto {}
162162
// CHECK-PRIVATE-NOT: IOIPublicStruct
163163
// CHECK-PUBLIC-NOT: IOIPublicStruct
164164

165+
@_spi(S)
166+
@frozen public struct SPIFrozenStruct {
167+
// CHECK-PRIVATE: struct SPIFrozenStruct
168+
// CHECK-PUBLIC-NOT: SPIFrozenStruct
169+
170+
var spiTypeInFrozen = SPIStruct()
171+
// CHECK-PRIVATE: @_spi(S) internal var spiTypeInFrozen
172+
173+
private var spiTypeInFrozen1: SPIClass
174+
// CHECK-PRIVATE: @_spi(S) private var spiTypeInFrozen1
175+
}
176+
165177
// The dummy conformance should be only in the private swiftinterface for
166178
// SPI extensions.
167179
@_spi(LocalSPI)

test/SPI/spi_client.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,16 @@ public func publicUseOfSPI(param: SPIClass) -> SPIClass {} // expected-error 2{{
5353
public func publicUseOfSPI2() -> [SPIClass] {} // expected-error {{cannot use class 'SPIClass' here; it is an SPI imported from 'SPIHelper'}}
5454

5555
@inlinable
56-
func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
56+
public func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
5757
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
5858
_ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
5959
_ = [SPIClass]() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
6060
}
61+
62+
@_spi(S)
63+
@inlinable
64+
public func inlinable() -> SPIClass {
65+
spiFunc()
66+
_ = SPIClass()
67+
_ = [SPIClass]()
68+
}

0 commit comments

Comments
 (0)