Skip to content

Commit 872f45d

Browse files
authored
Merge pull request swiftlang#65542 from tshortli/implicit-modify-inherit-spi
Sema: Inherit SPI groups when synthesizing modify accessor
2 parents 554f967 + f11eaf1 commit 872f45d

File tree

7 files changed

+81
-11
lines changed

7 files changed

+81
-11
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,3 +1494,15 @@ bool swift::addNonIsolatedToSynthesized(NominalTypeDecl *nominal,
14941494
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
14951495
return true;
14961496
}
1497+
1498+
void swift::applyInferredSPIAccessControlAttr(Decl *decl,
1499+
const Decl *inferredFromDecl,
1500+
ASTContext &ctx) {
1501+
auto spiGroups = inferredFromDecl->getSPIGroups();
1502+
if (spiGroups.empty())
1503+
return;
1504+
1505+
auto spiAttr =
1506+
SPIAccessControlAttr::create(ctx, SourceLoc(), SourceRange(), spiGroups);
1507+
decl->getAttrs().add(spiAttr);
1508+
}

lib/Sema/CodeSynthesis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ bool hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal);
8989
/// if an attribute was added.
9090
bool addNonIsolatedToSynthesized(NominalTypeDecl *nominal, ValueDecl *value);
9191

92+
/// Adds the `@_spi` groups from \p inferredFromDecl to \p decl.
93+
void applyInferredSPIAccessControlAttr(Decl *decl, const Decl *inferredFromDecl,
94+
ASTContext &ctx);
95+
9296
} // end namespace swift
9397

9498
#endif

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
222222
if (originKind == DisallowedOriginKind::None)
223223
return false;
224224

225+
auto diagName = D->getName();
226+
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
227+
// Only diagnose accessors if their disallowed origin kind differs from
228+
// that of their storage.
229+
if (getDisallowedOriginKind(accessor->getStorage(), where) == originKind)
230+
return false;
231+
232+
// For accessors, diagnose with the name of the storage instead of the
233+
// implicit '_'.
234+
diagName = accessor->getStorage()->getName();
235+
}
236+
225237
ASTContext &ctx = where.getDeclContext()->getASTContext();
226238

227239
auto fragileKind = where.getFragileFunctionKind();
@@ -233,7 +245,7 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
233245
diag::decl_from_hidden_module;
234246
ctx.Diags.diagnose(loc, errorOrWarning,
235247
D->getDescriptiveKind(),
236-
D->getName(),
248+
diagName,
237249
static_cast<unsigned>(*reason),
238250
definingModule->getName(),
239251
static_cast<unsigned>(originKind));
@@ -250,7 +262,7 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
250262
diag::inlinable_decl_ref_from_hidden_module;
251263

252264
ctx.Diags.diagnose(loc, errorOrWarning,
253-
D->getDescriptiveKind(), D->getName(),
265+
D->getDescriptiveKind(), diagName,
254266
fragileKind.getSelector(), definingModule->getName(),
255267
static_cast<unsigned>(originKind));
256268

@@ -265,11 +277,6 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
265277
bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
266278
const ValueDecl *D,
267279
const ExportContext &where) {
268-
// Accessors cannot have exportability that's different than the storage,
269-
// so skip them for now.
270-
if (isa<AccessorDecl>(D))
271-
return false;
272-
273280
if (!where.mustOnlyReferenceExportedDecls())
274281
return false;
275282

lib/Sema/TypeCheckStorage.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,12 @@ createCoroutineAccessorPrototype(AbstractStorageDecl *storage,
23242324
AvailabilityInference::applyInferredAvailableAttrs(accessor,
23252325
asAvailableAs, ctx);
23262326

2327+
// A modify coroutine should have the same SPI visibility as the setter.
2328+
if (kind == AccessorKind::Modify) {
2329+
if (FuncDecl *setter = storage->getParsedAccessor(AccessorKind::Set))
2330+
applyInferredSPIAccessControlAttr(accessor, setter, ctx);
2331+
}
2332+
23272333
finishImplicitAccessor(accessor, ctx);
23282334

23292335
return accessor;

test/SPI/local_spi_decls.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,18 @@ public func useOfSPITypeInvalid() -> SPIClass { fatalError() } // expected-error
2626
@_spi(S) public func spiUseOfInternalType() -> InternalClass { fatalError() } // expected-error{{function cannot be declared public because its result uses an internal type}}
2727
@_spi(S) public func spiUseOfPrivateType(_ a: PrivateClass) { fatalError() } // expected-error{{function cannot be declared public because its parameter uses a private type}}
2828

29+
public var globalArrayWithSPISetter: [Int] {
30+
get { fatalError() }
31+
@_spi(S) set {}
32+
}
33+
2934
@inlinable
3035
func inlinable() -> SPIClass { // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
3136
spiFunc() // expected-error {{global function 'spiFunc()' cannot be used in an '@inlinable' function because it is SPI}}
3237
_ = SPIClass() // expected-error {{class 'SPIClass' cannot be used in an '@inlinable' function because it is SPI}}
3338
// expected-error@-1 {{initializer 'init()' cannot be used in an '@inlinable' function because it is SPI}}
39+
globalArrayWithSPISetter = [] // expected-error {{setter 'globalArrayWithSPISetter' cannot be used in an '@inlinable' function because it is SPI}}
40+
globalArrayWithSPISetter.append(0) // expected-error {{setter 'globalArrayWithSPISetter' cannot be used in an '@inlinable' function because it is SPI}}
3441
}
3542

3643
@_spi(S) public struct SPIStruct {

test/SPI/private_swiftinterface.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,22 @@ public class SomeClass {
139139
}
140140

141141
public struct PublicStruct {
142+
@_spi(S) public var spiVar: SomeClass
143+
// CHECK-PRIVATE: @_spi(S) public var spiVar: {{.*}}.SomeClass
144+
// CHECK-PUBLIC-NOT: spiVar
145+
146+
public var publicVarWithSPISet: SomeClass {
147+
get { SomeClass() }
148+
@_spi(S) set {}
149+
}
150+
// CHECK-PRIVATE: public var publicVarWithSPISet: {{.*}}.SomeClass {
151+
// CHECK-PRIVATE-NEXT: get
152+
// CHECK-PRIVATE-NEXT: @_spi(S) set
153+
// CHECK-PRIVATE-NEXT: }
154+
// CHECK-PUBLIC: public var publicVarWithSPISet: {{.*}}.SomeClass {
155+
// CHECK-PUBLIC-NEXT: get
156+
// CHECK-PUBLIC-NEXT: }
157+
142158
@_spi(S) @Wrapper public var spiWrappedSimple: SomeClass
143159
// CHECK-PRIVATE: @_spi(S) @{{.*}}.Wrapper public var spiWrappedSimple: {{.*}}.SomeClass
144160
// CHECK-PUBLIC-NOT: spiWrappedSimple

test/api-digester/ignore-spi-by-given-group-name.swift

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,39 @@
22

33
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi-before.json %s -enable-library-evolution -DBASELINE -emit-tbd-path %t/abi-before.tbd
44
// RUN: %target-swift-frontend -emit-module -o %t/Foo.swiftmodule -emit-abi-descriptor-path %t/abi-after.json %s -enable-library-evolution -emit-tbd-path %t/abi-after.tbd
5-
// RUN: %api-digester -diagnose-sdk --input-paths %t/abi-before.json -input-paths %t/abi-after.json -abi -o %t/result.txt
6-
// RUN: %FileCheck %s -check-prefix CHECK_INCLUDE_SPI < %t/result.txt
5+
// RUN: %api-digester -diagnose-sdk --input-paths %t/abi-before.json -input-paths %t/abi-after.json -abi -o %t/include-result.txt
6+
// RUN: %FileCheck %s -check-prefix CHECK_INCLUDE_SPI < %t/include-result.txt
77

8-
// RUN: %api-digester -diagnose-sdk --input-paths %t/abi-before.json -input-paths %t/abi-after.json -abi -o %t/result.txt -ignore-spi-group secret
9-
// RUN: %FileCheck -check-prefix CHECK_EXCLUDE_SPI %s < %t/result.txt
8+
// RUN: %api-digester -diagnose-sdk --input-paths %t/abi-before.json -input-paths %t/abi-after.json -abi -o %t/exclude-result.txt -ignore-spi-group secret
9+
// RUN: %FileCheck -check-prefix CHECK_EXCLUDE_SPI %s < %t/exclude-result.txt
1010

1111
#if BASELINE
1212

13+
public struct Struct {
14+
public var x: Int {
15+
get { 0 }
16+
@_spi(secret) set {}
17+
}
18+
}
19+
1320
@_spi(secret)
1421
public func foo() {}
1522

1623
#else
1724

25+
public struct Struct {
26+
public var x: Int {
27+
get { 0 }
28+
}
29+
}
1830

1931
#endif
2032

33+
// CHECK_INCLUDE_SPI: Accessor Struct.x.Modify() has been removed
34+
// CHECK_EXCLUDE_SPI-NOT: Struct.x.Modify()
35+
36+
// CHECK_INCLUDE_SPI: Accessor Struct.x.Set() has been removed
37+
// CHECK_EXCLUDE_SPI-NOT: Struct.x.Set()
38+
2139
// CHECK_INCLUDE_SPI: Func foo() has been removed
2240
// CHECK_EXCLUDE_SPI-NOT: foo()

0 commit comments

Comments
 (0)