mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Adopt @unsafe throughout the standard library
Annotate all of the `Unsafe*` types and `unsafe` functions in the standard library (including concurrency, synchronization, etc.) as `@unsafe`. Add a few tests to ensure that we detect uses of these types in clients that have disabled unsafe code.
This commit is contained in:
@@ -628,6 +628,7 @@ function(_compile_swift_files
|
||||
list(APPEND swift_flags "-enable-experimental-feature" "NoncopyableGenerics2")
|
||||
list(APPEND swift_flags "-enable-experimental-feature" "SuppressedAssociatedTypes")
|
||||
list(APPEND swift_flags "-enable-experimental-feature" "SE427NoInferenceOnExtension")
|
||||
list(APPEND swift_flags "-enable-experimental-feature" "AllowUnsafeAttribute")
|
||||
|
||||
if(SWIFT_ENABLE_EXPERIMENTAL_NONESCAPABLE_TYPES)
|
||||
list(APPEND swift_flags "-enable-experimental-feature" "NonescapableTypes")
|
||||
|
||||
@@ -64,7 +64,7 @@ endif()
|
||||
list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS
|
||||
"-enable-experimental-feature"
|
||||
"IsolatedAny"
|
||||
)
|
||||
)
|
||||
|
||||
list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS
|
||||
"-D__STDC_WANT_LIB_EXT1__=1")
|
||||
|
||||
@@ -480,6 +480,7 @@ extension JobPriority: Comparable {
|
||||
/// without making other changes.
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct UnsafeContinuation<T, E: Error>: Sendable {
|
||||
@usableFromInline internal var context: Builtin.RawUnsafeContinuation
|
||||
|
||||
@@ -683,6 +684,7 @@ internal func _resumeUnsafeThrowingContinuationWithError<T>(
|
||||
/// - SeeAlso: `withCheckedThrowingContinuation(function:_:)`
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@unsafe
|
||||
public func withUnsafeContinuation<T>(
|
||||
isolation: isolated (any Actor)? = #isolation,
|
||||
_ fn: (UnsafeContinuation<T, Never>) -> Void
|
||||
@@ -719,6 +721,7 @@ public func withUnsafeContinuation<T>(
|
||||
/// - SeeAlso: `withCheckedThrowingContinuation(function:_:)`
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@unsafe
|
||||
public func withUnsafeThrowingContinuation<T>(
|
||||
isolation: isolated (any Actor)? = #isolation,
|
||||
_ fn: (UnsafeContinuation<T, Error>) -> Void
|
||||
|
||||
@@ -1033,6 +1033,7 @@ public func withUnsafeCurrentTask<T>(body: (UnsafeCurrentTask?) async throws ->
|
||||
/// [concurrency]: https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html
|
||||
/// [tspl]: https://docs.swift.org/swift-book/
|
||||
@available(SwiftStdlib 5.1, *)
|
||||
@unsafe
|
||||
public struct UnsafeCurrentTask {
|
||||
internal let _task: Builtin.NativeObject
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ extension _MutexHandle {
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
public borrowing func unsafeLock() {
|
||||
_lock()
|
||||
}
|
||||
@@ -182,6 +183,7 @@ extension _MutexHandle {
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
public borrowing func unsafeTryLock() -> Bool {
|
||||
_tryLock()
|
||||
}
|
||||
@@ -189,6 +191,7 @@ extension _MutexHandle {
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
@unsafe
|
||||
public borrowing func unsafeUnlock() {
|
||||
_unlock()
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public struct VolatileMappedRegister<Pointee> {
|
||||
let _rawPointer: Builtin.RawPointer
|
||||
|
||||
@_transparent
|
||||
@unsafe
|
||||
public init(unsafeBitPattern: UInt) {
|
||||
self._rawPointer = Builtin.inttoptr_Word(unsafeBitPattern._builtinWordValue)
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ func _canBeClass<T>(_: T.Type) -> Int8 {
|
||||
/// Returns: A new instance of type `U`, cast from `x`.
|
||||
@inlinable // unsafe-performance
|
||||
@_transparent
|
||||
@unsafe
|
||||
public func unsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
|
||||
_precondition(MemoryLayout<T>.size == MemoryLayout<U>.size,
|
||||
"Can't unsafeBitCast between types of different sizes")
|
||||
@@ -242,6 +243,7 @@ internal func _isClassOrObjCExistential<T>(_ x: T.Type) -> Bool {
|
||||
/// be either a class or a class protocol. Either T, U, or both may be
|
||||
/// optional references.
|
||||
@_transparent
|
||||
@unsafe
|
||||
public func _unsafeReferenceCast<T, U>(_ x: T, to: U.Type) -> U {
|
||||
return Builtin.castReference(x)
|
||||
}
|
||||
@@ -265,12 +267,14 @@ public func _unsafeReferenceCast<T, U>(_ x: T, to: U.Type) -> U {
|
||||
/// - type: The type `T` to which `x` is cast.
|
||||
/// - Returns: The instance `x`, cast to type `T`.
|
||||
@_transparent
|
||||
@unsafe
|
||||
public func unsafeDowncast<T: AnyObject>(_ x: AnyObject, to type: T.Type) -> T {
|
||||
_debugPrecondition(x is T, "invalid unsafeDowncast")
|
||||
return Builtin.castReference(x)
|
||||
}
|
||||
|
||||
@_transparent
|
||||
@unsafe
|
||||
public func _unsafeUncheckedDowncast<T: AnyObject>(_ x: AnyObject, to type: T.Type) -> T {
|
||||
_internalInvariant(x is T, "invalid unsafeDowncast")
|
||||
return Builtin.castReference(x)
|
||||
@@ -331,6 +335,7 @@ public func _onFastPath() {
|
||||
// Optimizer hint that the condition is true. The condition is unchecked.
|
||||
// The builtin acts as an opaque instruction with side-effects.
|
||||
@usableFromInline @_transparent
|
||||
@unsafe
|
||||
func _uncheckedUnsafeAssume(_ condition: Bool) {
|
||||
_ = Builtin.assume_Int1(condition._value)
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ public typealias CBool = Bool
|
||||
/// Opaque pointers are used to represent C pointers to types that
|
||||
/// cannot be represented in Swift, such as incomplete struct types.
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct OpaquePointer {
|
||||
@usableFromInline
|
||||
internal var _rawValue: Builtin.RawPointer
|
||||
|
||||
@@ -155,6 +155,7 @@ public func _getTypeByMangledNameInContext(
|
||||
/// Prevents performance diagnostics in the passed closure.
|
||||
@_alwaysEmitIntoClient
|
||||
@_semantics("no_performance_analysis")
|
||||
@unsafe
|
||||
public func _unsafePerformance<T>(_ c: () -> T) -> T {
|
||||
return c()
|
||||
}
|
||||
|
||||
@@ -338,6 +338,7 @@ extension Optional {
|
||||
/// will never be equal to `nil` and only after you've tried using the
|
||||
/// postfix `!` operator.
|
||||
@inlinable
|
||||
@unsafe
|
||||
public var unsafelyUnwrapped: Wrapped {
|
||||
@inline(__always)
|
||||
get {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/// When you use this type, you become partially responsible for
|
||||
/// keeping the object alive.
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct Unmanaged<Instance: AnyObject> {
|
||||
@usableFromInline
|
||||
internal unowned(unsafe) var _value: Instance
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
/// collection with an `${Self}` instance copies the instances out of the
|
||||
/// referenced memory and into the new collection.
|
||||
@frozen // unsafe-performance
|
||||
@unsafe
|
||||
public struct Unsafe${Mutable}BufferPointer<Element: ~Copyable>: Copyable {
|
||||
|
||||
@usableFromInline
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
/// let numberPointer = UnsafePointer<Int>(&number)
|
||||
/// // Accessing 'numberPointer' is undefined behavior.
|
||||
@frozen // unsafe-performance
|
||||
@unsafe
|
||||
public struct UnsafePointer<Pointee: ~Copyable>: Copyable {
|
||||
|
||||
/// The underlying raw (untyped) pointer.
|
||||
@@ -655,6 +656,7 @@ extension UnsafePointer where Pointee: ~Copyable {
|
||||
/// let numberPointer = UnsafeMutablePointer<Int>(&number)
|
||||
/// // Accessing 'numberPointer' is undefined behavior.
|
||||
@frozen // unsafe-performance
|
||||
@unsafe
|
||||
public struct UnsafeMutablePointer<Pointee: ~Copyable>: Copyable {
|
||||
/// The underlying raw (untyped) pointer.
|
||||
@_preInverseGenerics
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
/// destBytes[0..<n] = someBytes[n..<(n + n)]
|
||||
% end
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct Unsafe${Mutable}RawBufferPointer {
|
||||
@usableFromInline
|
||||
internal let _position, _end: Unsafe${Mutable}RawPointer?
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
/// let numberPointer = UnsafeRawPointer(&number)
|
||||
/// // Accessing 'numberPointer' is undefined behavior.
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct UnsafeRawPointer: _Pointer {
|
||||
|
||||
public typealias Pointee = UInt8
|
||||
@@ -773,6 +774,7 @@ extension UnsafeRawPointer {
|
||||
/// let numberPointer = UnsafeMutableRawPointer(&number)
|
||||
/// // Accessing 'numberPointer' is undefined behavior.
|
||||
@frozen
|
||||
@unsafe
|
||||
public struct UnsafeMutableRawPointer: _Pointer {
|
||||
|
||||
public typealias Pointee = UInt8
|
||||
|
||||
@@ -3,3 +3,5 @@ void unsafe_c_function(void) __attribute__((swift_attr("unsafe")));
|
||||
struct __attribute__((swift_attr("unsafe"))) UnsafeType {
|
||||
int field;
|
||||
};
|
||||
|
||||
void print_ints(int *ptr, int count);
|
||||
|
||||
@@ -4,4 +4,8 @@ import unsafe_decls
|
||||
|
||||
func testUnsafe(_ ut: UnsafeType) { // expected-error{{reference to unsafe struct 'UnsafeType'}}
|
||||
unsafe_c_function() // expected-error{{call to unsafe global function 'unsafe_c_function'}}
|
||||
|
||||
var array: [CInt] = [1, 2, 3, 4, 5]
|
||||
print_ints(&array, CInt(array.count))
|
||||
// expected-error@-1{{call to global function 'print_ints' involves unsafe type 'UnsafeMutablePointer<Int32>'}}
|
||||
}
|
||||
|
||||
17
test/Unsafe/unsafe_stdlib.swift
Normal file
17
test/Unsafe/unsafe_stdlib.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
// RUN: %target-typecheck-verify-swift -enable-experimental-feature AllowUnsafeAttribute -enable-experimental-feature DisallowUnsafe
|
||||
|
||||
// Make sure everything compiles without error when unsafe code is allowed.
|
||||
// RUN: %target-swift-frontend -typecheck -enable-experimental-feature AllowUnsafeAttribute %s
|
||||
|
||||
func test(
|
||||
x: OpaquePointer, // expected-error{{reference to unsafe struct 'OpaquePointer'}}
|
||||
other: UnsafeMutablePointer<Int> // expected-error{{reference to unsafe generic struct 'UnsafeMutablePointer'}}
|
||||
) {
|
||||
var array = [1, 2, 3]
|
||||
// expected-error@+1{{call to instance method 'withUnsafeBufferPointer' involves unsafe type 'UnsafeBufferPointer<Int>'}}
|
||||
array.withUnsafeBufferPointer{ buffer in // expected-note{{'buffer' declared here}}
|
||||
print(buffer) // expected-error{{reference to parameter 'buffer' involves unsafe type 'UnsafeBufferPointer<Int>'}}
|
||||
}
|
||||
array.append(4)
|
||||
_ = array
|
||||
}
|
||||
Reference in New Issue
Block a user