Skip to content

Commit 5f5372a

Browse files
committed
Sema: Don't check SPI violations in diagnoseInlinableDeclRefAccess()
There's no need to check for that here, because we also run diagnoseDeclRefExportability() on declarations referenced from inlinable code. This changes some diagnostics; we now produce the same diagnostic for references to SPI types in declaration signatures and for references to non-type SPI declarations in inlinable function bodies. Also note that the old inlinable reference diagnostic no longer has to handle the 'public' and 'open' access levels, which previously happened for '@_spi'; so I changed those entries in the %select to %error.
1 parent b3dadc8 commit 5f5372a

File tree

7 files changed

+153
-71
lines changed

7 files changed

+153
-71
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5061,12 +5061,12 @@ ERROR(local_type_in_inlinable_function,
50615061
(Identifier, unsigned))
50625062

50635063
ERROR(resilience_decl_unavailable,
5064-
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and "
5064+
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|%error|%error}2 and "
50655065
"cannot be referenced from " FRAGILE_FUNC_KIND "3",
50665066
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
50675067

50685068
WARNING(resilience_decl_unavailable_warn,
5069-
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|'@_spi'|'@_spi'}2 and "
5069+
none, DECL_OR_ACCESSOR "4 %1 is %select{private|fileprivate|internal|%error|%error}2 and "
50705070
"should not be referenced from " FRAGILE_FUNC_KIND "3",
50715071
(DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool))
50725072

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
4040

4141
auto *DC = where.getDeclContext();
4242

43-
// Public declarations or SPI used from SPI are OK.
43+
// Public declarations are OK, even if they're SPI or came from an
44+
// implementation-only import. We'll diagnose exportability violations
45+
// from diagnoseDeclRefExportability().
4446
if (D->getFormalAccessScope(/*useDC=*/nullptr,
45-
fragileKind.allowUsableFromInline).isPublic() &&
46-
!(D->isSPI() && !DC->getInnermostDeclarationDeclContext()->isSPI()))
47+
fragileKind.allowUsableFromInline).isPublic())
4748
return false;
4849

4950
auto &Context = DC->getASTContext();

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,15 @@ static void forEachOuterDecl(DeclContext *DC, Fn fn) {
148148
}
149149
}
150150

151-
static void computeExportContextBits(Decl *D,
152-
bool *implicit, bool *deprecated,
151+
static void computeExportContextBits(ASTContext &Ctx, Decl *D,
152+
bool *spi, bool *implicit, bool *deprecated,
153153
Optional<PlatformKind> *unavailablePlatformKind) {
154+
if (D->isSPI())
155+
*spi = true;
156+
154157
if (D->isImplicit())
155158
*implicit = true;
156159

157-
auto &Ctx = D->getASTContext();
158-
159160
if (D->getAttrs().getDeprecated(Ctx))
160161
*deprecated = true;
161162

@@ -166,66 +167,55 @@ static void computeExportContextBits(Decl *D,
166167
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
167168
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
168169
if (auto *VD = PBD->getAnchoringVarDecl(i))
169-
computeExportContextBits(VD, implicit, deprecated,
170+
computeExportContextBits(Ctx, VD, spi, implicit, deprecated,
170171
unavailablePlatformKind);
171172
}
172173
}
173174
}
174175

175176
ExportContext ExportContext::forDeclSignature(Decl *D) {
177+
auto &Ctx = D->getASTContext();
178+
179+
auto *DC = D->getInnermostDeclContext();
180+
auto fragileKind = DC->getFragileFunctionKind();
181+
182+
bool spi = false;
176183
bool implicit = false;
177184
bool deprecated = false;
178185
Optional<PlatformKind> unavailablePlatformKind;
179-
computeExportContextBits(D, &implicit, &deprecated,
186+
computeExportContextBits(Ctx, D, &spi, &implicit, &deprecated,
180187
&unavailablePlatformKind);
181188
forEachOuterDecl(D->getDeclContext(),
182189
[&](Decl *D) {
183-
computeExportContextBits(D, &implicit, &deprecated,
190+
computeExportContextBits(Ctx, D,
191+
&spi, &implicit, &deprecated,
184192
&unavailablePlatformKind);
185193
});
186194

187-
auto *DC = D->getInnermostDeclContext();
188-
auto fragileKind = DC->getFragileFunctionKind();
189-
190-
bool spi = D->isSPI();
191-
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
192-
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
193-
if (auto *VD = PBD->getAnchoringVarDecl(i)) {
194-
if (VD->isSPI()) {
195-
spi = true;
196-
break;
197-
}
198-
}
199-
}
200-
}
201-
202195
bool exported = ::isExported(D);
203196

204197
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated,
205198
unavailablePlatformKind);
206199
}
207200

208201
ExportContext ExportContext::forFunctionBody(DeclContext *DC) {
202+
auto &Ctx = DC->getASTContext();
203+
204+
auto fragileKind = DC->getFragileFunctionKind();
205+
206+
bool spi = false;
209207
bool implicit = false;
210208
bool deprecated = false;
211209
Optional<PlatformKind> unavailablePlatformKind;
212210
forEachOuterDecl(DC,
213211
[&](Decl *D) {
214-
computeExportContextBits(D, &implicit, &deprecated,
212+
computeExportContextBits(Ctx, D,
213+
&spi, &implicit, &deprecated,
215214
&unavailablePlatformKind);
216215
});
217216

218-
auto fragileKind = DC->getFragileFunctionKind();
219-
220-
bool spi = false;
221217
bool exported = false;
222218

223-
if (auto *D = DC->getInnermostDeclarationDeclContext()) {
224-
spi = D->isSPI();
225-
} else {
226-
assert(fragileKind.kind == FragileFunctionKind::None);
227-
}
228-
229219
return ExportContext(DC, fragileKind, spi, exported, implicit, deprecated,
230220
unavailablePlatformKind);
231221
}

test/SPI/implementation_only_spi_import_exposability.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public struct PublicStruct : IOIProtocol, SPIProtocol { // expected-error {{cann
3636

3737
@inlinable
3838
public func publicInlinable() {
39-
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
39+
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
4040
ioiFunc() // expected-error {{global function 'ioiFunc()' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
41-
let _ = SPIStruct() // expected-error {{struct 'SPIStruct' is '@_spi' and cannot be referenced from an '@inlinable' function}}
42-
// expected-error@-1 {{initializer 'init()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
41+
let _ = SPIStruct() // expected-error {{struct 'SPIStruct' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
42+
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
4343
let _ = IOIStruct() // expected-error {{struct 'IOIStruct' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
4444
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because 'Lib' was imported implementation-only}}
4545
}

test/SPI/local_spi_decls.swift

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,14 @@
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 2 {{global function 'spiFunc()' is not '@usableFromInline' or public}}
10+
@_spi(MySPI) public func spiFunc() {}
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

1616
@_spi(S) public class SPIClass { // expected-note 6 {{type declared here}}
17-
// expected-note@-1 3 {{class 'SPIClass' is not '@usableFromInline' or public}}
18-
// expected-note@-2 {{class 'SPIClass' is not public}}
1917
public init() {}
20-
// expected-note@-1 2 {{initializer 'init()' is not '@usableFromInline' or public}}
21-
// expected-note@-2 {{initializer 'init()' is not public}}
2218
}
2319
class InternalClass {} // expected-note 2 {{type declared here}}
2420
private class PrivateClass {} // expected-note 2 {{type declared here}}
@@ -31,28 +27,24 @@ public func useOfSPITypeInvalid() -> SPIClass { fatalError() } // expected-error
3127
@_spi(S) public func spiUseOfPrivateType(_ a: PrivateClass) { fatalError() } // expected-error{{function cannot be declared public because its parameter uses a private type}}
3228

3329
@inlinable
34-
func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
35-
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
36-
_ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
37-
// expected-error@-1 {{initializer 'init()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
30+
func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
31+
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because it is SPI}}
32+
_ = SPIClass() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
33+
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because it is SPI}}
3834
}
3935

40-
@_spi(S) public struct SPIStruct { // expected-note 2 {{struct 'SPIStruct' is not '@usableFromInline' or public}}
41-
// expected-note@-1 2 {{type declared here}}
42-
// FIXME: Misleading diagnostic here
36+
@_spi(S) public struct SPIStruct {
37+
// expected-note@-1 {{type declared here}}
4338
public init() {}
44-
// expected-note@-1 2 {{initializer 'init()' is not '@usableFromInline' or public}}
4539
}
4640

4741
@frozen public struct FrozenStruct {
48-
@_spi(S) public var spiInFrozen = SPIStruct() // expected-error {{struct 'SPIStruct' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
42+
@_spi(S) public var spiInFrozen = SPIStruct()
4943
// expected-error@-1 {{stored property 'spiInFrozen' cannot be declared '@_spi' in a '@frozen' struct}}
50-
// expected-error@-2 {{cannot use struct 'SPIStruct' here; it is SPI}}
51-
// expected-error@-3 {{initializer 'init()' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
5244

53-
var spiTypeInFrozen = 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' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
5446
// expected-error@-1 {{cannot use struct 'SPIStruct' here; it is SPI}}
55-
// expected-error@-2 {{initializer 'init()' is '@_spi' and cannot be referenced from a property initializer in a '@frozen' type}}
47+
// expected-error@-2 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
5648

5749
private var spiTypeInFrozen1: SPIClass // expected-error {{cannot use class 'SPIClass' here; it is SPI}}
5850
}
@@ -109,17 +101,17 @@ public struct NestedParent {
109101
}
110102

111103
public func publicFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {} // expected-error {{cannot use class 'SPIClass' here; it is SPI}}
112-
// expected-error@-1 {{class 'SPIClass' is '@_spi' and cannot be referenced from a default argument value}}
113-
// expected-error@-2 {{initializer 'init()' is '@_spi' and cannot be referenced from a default argument value}}
104+
// expected-error@-1 {{class 'SPIClass' cannot be used in a default argument value because it is SPI}}
105+
// expected-error@-2 {{initializer 'init()' cannot be used in a default argument value because it is SPI}}
114106

115107
@_spi(S)
116108
public func spiFuncWithDefaultValue(_ p: SPIClass = SPIClass()) {}
117109

118110
@inlinable
119111
public func inlinablePublic() {
120-
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
121-
let _ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
122-
// expected-error@-1 {{initializer 'init()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
112+
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because it is SPI}}
113+
let _ = SPIClass() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
114+
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because it is SPI}}
123115
}
124116

125117
@_spi(S)

test/SPI/spi_client.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ 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-
public func inlinable1() -> SPIClass { // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
57-
spiFunc() // expected-error {{global function 'spiFunc()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
58-
_ = SPIClass() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
59-
// expected-error@-1 {{initializer 'init()' is '@_spi' and cannot be referenced from an '@inlinable' function}}
60-
_ = [SPIClass]() // expected-error {{class 'SPIClass' is '@_spi' and cannot be referenced from an '@inlinable' function}}
56+
public func inlinable1() -> SPIClass { // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
57+
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
58+
_ = SPIClass() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
59+
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
60+
_ = [SPIClass]() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is an SPI imported from 'SPIHelper'}}
6161
}
6262

6363
@_spi(S)

test/SPI/spi_members.swift

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,110 @@
11
// RUN: %target-typecheck-verify-swift
22

3+
@propertyWrapper
4+
public struct Wrapper<T> {
5+
public init(wrappedValue: T) {}
6+
7+
public var wrappedValue: T { fatalError() }
8+
}
9+
310
@_spi(Foo)
4-
public class Bar {}
11+
public class Bar {
12+
// expected-note@-1 11{{type declared here}}
13+
14+
public init() {}
15+
}
16+
17+
public struct Resilient {
18+
public init() {}
19+
20+
@_spi(Foo) public func method(_: Bar) {}
21+
@_spi(Foo) public var computedProperty: Bar { Bar() }
22+
23+
@_spi(Foo) public var storedProperty1: Bar
24+
@_spi(Foo) public var storedProperty2 = Bar()
25+
@_spi(Foo) public lazy var lazyProperty1 = Bar()
26+
@_spi(Foo) public lazy var lazyProperty2: Bar = Bar()
27+
@_spi(Foo) @Wrapper public var wrappedProperty1: Bar
28+
@_spi(Foo) @Wrapper public var wrappedProperty2 = Bar()
29+
}
530

6-
public struct Foo {
31+
@frozen public struct Good {
732
public init() {}
833

934
@_spi(Foo) public func method(_: Bar) {}
10-
@_spi(Foo) public var property: Bar { Bar() }
35+
@_spi(Foo) public var computedProperty: Bar { Bar() }
36+
37+
@_spi(Foo) public var storedProperty1: Bar
38+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
39+
// expected-error@-2 {{stored property 'storedProperty1' cannot be declared '@_spi' in a '@frozen' struct}}
40+
41+
@_spi(Foo) public var storedProperty2 = Bar()
42+
// expected-error@-1 {{stored property 'storedProperty2' cannot be declared '@_spi' in a '@frozen' struct}}
43+
44+
@_spi(Foo) public lazy var lazyProperty1 = Bar()
45+
@_spi(Foo) public lazy var lazyProperty2: Bar = Bar()
46+
@_spi(Foo) @Wrapper public var wrappedProperty1: Bar
47+
@_spi(Foo) @Wrapper public var wrappedProperty2 = Bar()
48+
}
49+
50+
@frozen public struct Bad {
51+
public init() {}
52+
53+
public func method(_: Bar) {} // expected-error {{cannot use class 'Bar' here; it is SPI}}
54+
55+
public var storedProperty1: Bar
56+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
57+
58+
public var storedProperty2 = Bar()
59+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
60+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
61+
// expected-error@-3 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
62+
63+
public var computedProperty: Bar { Bar() } // expected-error {{cannot use class 'Bar' here; it is SPI}}
64+
65+
public lazy var lazyProperty1 = Bar() // expected-error {{cannot use class 'Bar' here; it is SPI}}
66+
// expected-error@-1 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
67+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
68+
69+
public lazy var lazyProperty2: Bar = Bar() // expected-error {{cannot use class 'Bar' here; it is SPI}}
70+
// expected-error@-1 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
71+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
72+
73+
@Wrapper public var wrappedProperty1: Bar
74+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
75+
76+
@Wrapper public var wrappedProperty2 = Bar()
77+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
78+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
79+
// expected-error@-3 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
80+
}
81+
82+
@frozen public struct BadPrivate {
83+
private init() {}
84+
85+
private func method(_: Bar) {}
86+
87+
private var storedProperty1: Bar
88+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
89+
90+
private var storedProperty2 = Bar()
91+
// expected-error@-1 {{cannot use class 'Bar' here; it is SPI}}
92+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
93+
// expected-error@-3 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
94+
95+
private var computedProperty: Bar { Bar() }
96+
97+
private lazy var lazyProperty1 = Bar()
98+
// expected-error@-1 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
99+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
100+
101+
private lazy var lazyProperty2: Bar = Bar()
102+
// expected-error@-1 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
103+
// expected-error@-2 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
104+
105+
@Wrapper private var wrappedProperty1: Bar
106+
107+
@Wrapper private var wrappedProperty2 = Bar()
108+
// expected-error@-1 {{class 'Bar' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
109+
// expected-error@-2 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
11110
}

0 commit comments

Comments
 (0)