Skip to content

Commit 38cbc7d

Browse files
committed
Diagnosing a private setter being accessed from the inlinable function.
rdar://81879146
1 parent 3754042 commit 38cbc7d

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,24 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
8383
D->getFormalAccessScope(/*useDC=*/DC,
8484
/*allowUsableFromInline=*/true);
8585

86-
// Public declarations are OK, even if they're SPI or came from an
87-
// implementation-only import. We'll diagnose exportability violations
88-
// from diagnoseDeclRefExportability().
89-
if (declAccessScope.isPublic())
86+
if (declAccessScope.isPublic()) {
87+
// Diagnose private setters accessed from inlinable functions
88+
if (auto *accessor = dyn_cast<AccessorDecl>(D)) {
89+
if (accessor->getAccessorKind() == AccessorKind::Set) {
90+
auto storage = accessor->getStorage();
91+
if (accessor->getFormalAccess() < storage->getFormalAccess()) {
92+
auto diagID = diag::resilience_decl_unavailable;
93+
Context.Diags.diagnose(loc, diagID, D, accessor->getFormalAccess(),
94+
fragileKind.getSelector());
95+
Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D);
96+
}
97+
}
98+
}
99+
// Public declarations are OK, even if they're SPI or came from an
100+
// implementation-only import. We'll diagnose exportability violations
101+
// from diagnoseDeclRefExportability().
90102
return false;
103+
}
91104

92105
// Dynamic declarations were mistakenly not checked in Swift 4.2.
93106
// Do enforce the restriction even in pre-Swift-5 modes if the module we're

test/attr/attr_inlinable.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,43 @@ public struct HasInternalSetProperty {
314314
}
315315
}
316316

317+
public struct HasUsableFromInlinePrivateSetProperty {
318+
@usableFromInline private(set) var bytes: UnsafeMutableRawPointer // expected-note 2 {{setter for property 'bytes' is not '@usableFromInline' or public}}
319+
public init() {
320+
self.bytes = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 8)
321+
}
322+
@usableFromInline
323+
func modifyPointer(_ ptr: inout UnsafeMutableRawPointer) {
324+
ptr = UnsafeMutableRawPointer.allocate(byteCount: 1, alignment: 1)
325+
}
326+
@usableFromInline
327+
func readPointer(_ ptr: UnsafeMutableRawPointer) {
328+
_ = ptr
329+
}
330+
// writes should trigger diagnostic
331+
@inlinable
332+
public mutating func writeDirect() {
333+
self.bytes = UnsafeMutableRawPointer.allocate(byteCount: 2048, alignment: 8) // expected-error {{setter for property 'bytes' is private and cannot be referenced from an '@inlinable' function}}
334+
}
335+
@inlinable
336+
public mutating func writeFunc() {
337+
modifyPointer(&self.bytes) // expected-error {{setter for property 'bytes' is private and cannot be referenced from an '@inlinable' function}}
338+
}
339+
// reads should be ok
340+
@inlinable
341+
public func usesBytes() -> UnsafeMutableRawPointer {
342+
_ = self.bytes
343+
}
344+
@inlinable
345+
public func readsViaLoad() -> Int {
346+
return self.bytes.load(as: Int.self)
347+
}
348+
@inlinable
349+
public func readsViaFunc() {
350+
readPointer(self.bytes) // OK
351+
}
352+
}
353+
317354
@usableFromInline protocol P {
318355
typealias T = Int
319356
}

0 commit comments

Comments
 (0)