diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index eceb7a9ed15b3..528fda56972f4 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -83,11 +83,24 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, D->getFormalAccessScope(/*useDC=*/DC, /*allowUsableFromInline=*/true); - // Public declarations are OK, even if they're SPI or came from an - // implementation-only import. We'll diagnose exportability violations - // from diagnoseDeclRefExportability(). - if (declAccessScope.isPublic()) + if (declAccessScope.isPublic()) { + // Diagnose private setters accessed from inlinable functions + if (auto *accessor = dyn_cast(D)) { + if (accessor->getAccessorKind() == AccessorKind::Set) { + auto storage = accessor->getStorage(); + if (accessor->getFormalAccess() < storage->getFormalAccess()) { + auto diagID = diag::resilience_decl_unavailable; + Context.Diags.diagnose(loc, diagID, D, accessor->getFormalAccess(), + fragileKind.getSelector()); + Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D); + } + } + } + // Public declarations are OK, even if they're SPI or came from an + // implementation-only import. We'll diagnose exportability violations + // from diagnoseDeclRefExportability(). return false; + } // Dynamic declarations were mistakenly not checked in Swift 4.2. // Do enforce the restriction even in pre-Swift-5 modes if the module we're diff --git a/test/attr/attr_inlinable.swift b/test/attr/attr_inlinable.swift index ea71c90a854fe..f58bc24b9a141 100644 --- a/test/attr/attr_inlinable.swift +++ b/test/attr/attr_inlinable.swift @@ -314,6 +314,43 @@ public struct HasInternalSetProperty { } } +public struct HasUsableFromInlinePrivateSetProperty { + @usableFromInline private(set) var bytes: UnsafeMutableRawPointer // expected-note 2 {{setter for property 'bytes' is not '@usableFromInline' or public}} + public init() { + self.bytes = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 8) + } + @usableFromInline + func modifyPointer(_ ptr: inout UnsafeMutableRawPointer) { + ptr = UnsafeMutableRawPointer.allocate(byteCount: 1, alignment: 1) + } + @usableFromInline + func readPointer(_ ptr: UnsafeMutableRawPointer) { + _ = ptr + } + // writes should trigger diagnostic + @inlinable + public mutating func writeDirect() { + self.bytes = UnsafeMutableRawPointer.allocate(byteCount: 2048, alignment: 8) // expected-error {{setter for property 'bytes' is private and cannot be referenced from an '@inlinable' function}} + } + @inlinable + public mutating func writeFunc() { + modifyPointer(&self.bytes) // expected-error {{setter for property 'bytes' is private and cannot be referenced from an '@inlinable' function}} + } + // reads should be ok + @inlinable + public func usesBytes() -> UnsafeMutableRawPointer { + _ = self.bytes + } + @inlinable + public func readsViaLoad() -> Int { + return self.bytes.load(as: Int.self) + } + @inlinable + public func readsViaFunc() { + readPointer(self.bytes) // OK + } +} + @usableFromInline protocol P { typealias T = Int }