Skip to content

Commit aa75341

Browse files
committed
Sema: Accessors's SPI are tied to the attributes on the storage
Recent changes started using SPIGroupRequest on accessors specifically to verify access to the wrappedValue of PropertyWrappers within the direct access logic on variables using the property wrapper. Update SPIGroupRequest to support this request and the type-checking logic to accept the @_spi attribute on internal usable from inline accessors. rdar://141964200
1 parent 24a74af commit aa75341

File tree

4 files changed

+161
-2
lines changed

4 files changed

+161
-2
lines changed

lib/AST/Module.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,6 +3191,14 @@ SPIGroupsRequest::evaluate(Evaluator &evaluator, const Decl *decl) const {
31913191
spiGroups.insert(originalSPIs.begin(), originalSPIs.end());
31923192
}
31933193

3194+
// Accessors get the SPI groups from the PBD.
3195+
if (auto AD = dyn_cast<AccessorDecl>(decl))
3196+
if (auto VD = dyn_cast<VarDecl>(AD->getStorage()))
3197+
if (auto *PBD = VD->getParentPatternBinding()) {
3198+
auto moreGroups = PBD->getSPIGroups();
3199+
spiGroups.insert(moreGroups.begin(), moreGroups.end());
3200+
}
3201+
31943202
// If there is no local SPI information, look at the context.
31953203
if (spiGroups.empty()) {
31963204

lib/Sema/TypeCheckAttr.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,8 +1412,17 @@ void AttributeChecker::visitSPIAccessControlAttr(SPIAccessControlAttr *attr) {
14121412
// VD must be public or open to use an @_spi attribute.
14131413
auto declAccess = VD->getFormalAccess();
14141414
auto DC = VD->getDeclContext()->getAsDecl();
1415-
if (declAccess < AccessLevel::Public &&
1416-
!VD->getAttrs().hasAttribute<UsableFromInlineAttr>() &&
1415+
1416+
AbstractStorageDecl *storage = nullptr;
1417+
if (auto *AD = dyn_cast<AccessorDecl>(VD))
1418+
storage = AD->getStorage();
1419+
1420+
auto canUseAttr = [](ValueDecl *VD) {
1421+
return VD->getFormalAccess() >= AccessLevel::Public ||
1422+
VD->getAttrs().hasAttribute<UsableFromInlineAttr>();
1423+
};
1424+
if (!canUseAttr(VD) &&
1425+
!(storage && canUseAttr(storage)) &&
14171426
!(DC && DC->isSPI())) {
14181427
diagnoseAndRemoveAttr(attr,
14191428
diag::spi_attribute_on_non_public,

test/SPI/spi_internal_accessor.swift

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module %s -module-name main \
3+
// RUN: -swift-version 6 -enable-library-evolution \
4+
// RUN: -emit-module-interface-path %t/main.swiftinterface \
5+
// RUN: -emit-private-module-interface-path %t/main.private.swiftinterface
6+
7+
// RUN: %FileCheck %s -check-prefix CHECK-PUBLIC --input-file %t/main.swiftinterface
8+
// CHECK-PUBLIC-NOT: @_spi
9+
10+
// RUN: %FileCheck %s -check-prefix CHECK-PRIVATE --input-file %t/main.private.swiftinterface
11+
12+
// RUN: %target-swift-typecheck-module-from-interface(%t/main.swiftinterface) -module-name main
13+
// RUN: %target-swift-typecheck-module-from-interface(%t/main.private.swiftinterface) -module-name main
14+
15+
public struct S {
16+
@usableFromInline @_spi(X)
17+
internal var v: Int {
18+
get { return 42 }
19+
}
20+
}
21+
22+
extension UnsafeMutablePointer {
23+
@_spi(X) @available(swift, obsoleted: 1)
24+
// CHECK-PRIVATE: @_spi(X) @available(swift, obsoleted: 1)
25+
@usableFromInline
26+
// CHECK-PRIVATE: @usableFromInline
27+
internal var pointee: Pointee {
28+
// CHECK-PRIVATE: internal var pointee: Pointee {
29+
@_transparent unsafeAddress {
30+
// CHECK-PRIVATE: @_spi(X) @_transparent unsafeAddress {
31+
return UnsafePointer(self)
32+
// CHECK-PRIVATE: return UnsafePointer(self)
33+
}
34+
// CHECK-PRIVATE: }
35+
@_transparent nonmutating unsafeMutableAddress {
36+
// CHECK-PRIVATE: @_transparent nonmutating unsafeMutableAddress {
37+
return self
38+
// CHECK-PRIVATE: return self
39+
}
40+
// CHECK-PRIVATE: }
41+
}
42+
// CHECK-PRIVATE: }
43+
}
44+
45+
extension UnsafeMutablePointer {
46+
@_spi(X)
47+
// CHECK-PRIVATE: @_spi(X)
48+
public var pointee2: Pointee {
49+
// CHECK-PRIVATE: public var pointee2: Pointee {
50+
unsafeAddress {
51+
// CHECK-PRIVATE: unsafeAddress
52+
return UnsafePointer(self)
53+
}
54+
@_transparent nonmutating unsafeMutableAddress {
55+
// CHECK-PRIVATE: @_transparent nonmutating unsafeMutableAddress {
56+
return self
57+
// CHECK-PRIVATE: return self
58+
}
59+
// CHECK-PRIVATE: }
60+
}
61+
// CHECK-PRIVATE: }
62+
}
63+
64+
65+
@_spi(Foo) @propertyWrapper public struct SPIWrapper<T> {
66+
// CHECK-PRIVATE: @_spi(Foo) @propertyWrapper public struct SPIWrapper<T> {
67+
public init(wrappedValue: T) {}
68+
// CHECK-PRIVATE: @_spi(Foo) public init(wrappedValue: T)
69+
public var wrappedValue: T { fatalError() }
70+
// CHECK-PRIVATE: @_spi(Foo) public var wrappedValue: T {
71+
// CHECK-PRIVATE: @_spi(Foo) get
72+
// CHECK-PRIVATE: }
73+
// CHECK-PRIVATE: }
74+
}
75+
76+
public struct InternalSet {
77+
// CHECK-PRIVATE: public struct InternalSet {
78+
@_spi(X) public internal(set) var long: Int {
79+
get { 0 }
80+
set { }
81+
}
82+
// CHECK-PRIVATE: @_spi(X) public var long: Swift.Int {
83+
// CHECK-PRIVATE: @_spi(X) get
84+
// CHECK-PRIVATE: }
85+
86+
@_spi(X) public internal(set) var short: Int
87+
// CHECK-PRIVATE: @_spi(X) public var short: Swift.Int {
88+
// CHECK-PRIVATE: get
89+
// CHECK-PRIVATE: }
90+
}
91+
// CHECK-PRIVATE: }

test/SPI/spi_members.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,29 @@ public struct Wrapper<T> {
77
public var wrappedValue: T { fatalError() }
88
}
99

10+
@_spi(Foo)
11+
@propertyWrapper
12+
public struct SPIWrapper<T> {
13+
// expected-note@-1 2 {{generic struct declared here}}
14+
public init(wrappedValue: T) {}
15+
16+
public var wrappedValue: T { fatalError() }
17+
// expected-note@-1 2 {{property declared here}}
18+
}
19+
1020
@_spi(Foo)
1121
public class SPIType {
1222
// expected-note@-1 16{{class declared here}}
1323

1424
public init() {}
1525
}
1626

27+
public struct PublicType {
28+
public init() {}
29+
30+
@_spi(Foo) public func spiFunc() {}
31+
}
32+
1733
public struct ResilientStructSPIMembers {
1834
public init() {}
1935

@@ -26,6 +42,34 @@ public struct ResilientStructSPIMembers {
2642
@_spi(Foo) public lazy var lazyProperty2: SPIType = SPIType()
2743
@_spi(Foo) @Wrapper public var wrappedProperty1: SPIType
2844
@_spi(Foo) @Wrapper public var wrappedProperty2 = SPIType()
45+
@_spi(Foo) @SPIWrapper public var wrappedProperty3 = SPIType()
46+
47+
@SPIWrapper public var wrappedProperty4: PublicType
48+
// expected-error@-1 {{cannot use generic struct 'SPIWrapper' as property wrapper here; it is SPI}}
49+
// expected-error@-2 {{cannot use property 'wrappedValue' here; it is SPI}}
50+
51+
@_spi(Foo) public var inlinableGet: Int {
52+
@inlinable
53+
get {
54+
let _ = SPIType()
55+
let t = PublicType()
56+
t.spiFunc()
57+
return 42
58+
}
59+
}
60+
61+
public var inlinablePublicGet: Int {
62+
@inlinable
63+
get {
64+
let _ = SPIType()
65+
// expected-error@-1 {{class 'SPIType' cannot be used in an '@inlinable' function because it is SPI}}
66+
// expected-error@-2 {{initializer 'init()' cannot be used in an '@inlinable' function because it is SPI}}
67+
let t = PublicType()
68+
t.spiFunc()
69+
// expected-error@-1 {{instance method 'spiFunc()' cannot be used in an '@inlinable' function because it is SPI}}
70+
return 42
71+
}
72+
}
2973
}
3074

3175
@frozen public struct FrozenStructSPIMembers {
@@ -53,6 +97,9 @@ public struct ResilientStructSPIMembers {
5397

5498
@_spi(Foo) @Wrapper public var wrappedProperty2 = SPIType()
5599
// expected-error@-1 {{stored property 'wrappedProperty2' cannot be declared '@_spi' in a '@frozen' struct}}
100+
101+
@_spi(Foo) @SPIWrapper public var wrappedProperty3 = SPIType()
102+
// expected-error@-1 {{stored property 'wrappedProperty3' cannot be declared '@_spi' in a '@frozen' struct}}
56103
}
57104

58105
@frozen public struct FrozenStructPublicMembers {
@@ -81,6 +128,10 @@ public struct ResilientStructSPIMembers {
81128
// expected-error@-1 {{cannot use class 'SPIType' here; it is SPI}}
82129
// expected-error@-2 {{class 'SPIType' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
83130
// expected-error@-3 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because it is SPI}}
131+
132+
@SPIWrapper public var wrappedProperty3: PublicType
133+
// expected-error@-1 {{cannot use generic struct 'SPIWrapper' as property wrapper here; it is SPI}}
134+
// expected-error@-2 {{cannot use property 'wrappedValue' here; it is SPI}}
84135
}
85136

86137
@frozen public struct FrozenStructPrivateMembers {

0 commit comments

Comments
 (0)