Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions stdlib/public/core/UnsafeRawPointer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,9 @@ extension UnsafeRawPointer {
/// `offset`. The returned instance is memory-managed and unassociated
/// with the value in the memory referenced by this pointer.
@inlinable
public func load<T>(
@_preInverseGenerics
@lifetime(borrow self)
public func load<T: ~Escapable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
Expand Down Expand Up @@ -488,7 +490,9 @@ extension UnsafeRawPointer {
/// with the value in the range of memory referenced by this pointer.
@inlinable
@_alwaysEmitIntoClient
public func loadUnaligned<T: BitwiseCopyable>(
@_preInverseGenerics
@lifetime(borrow self)
public func loadUnaligned<T: BitwiseCopyable & ~Escapable>(
fromByteOffset offset: Int = 0,
as type: T.Type
) -> T {
Expand Down Expand Up @@ -559,7 +563,7 @@ extension UnsafeRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedUp<T: ~Copyable>(for type: T.Type) -> Self {
public func alignedUp<T: ~Copyable & ~Escapable>(for type: T.Type) -> Self {
let mask = UInt(Builtin.alignof(T.self)) &- 1
let bits = (UInt(Builtin.ptrtoint_Word(_rawValue)) &+ mask) & ~mask
_debugPrecondition(bits != 0, "Overflow in pointer arithmetic")
Expand All @@ -577,7 +581,7 @@ extension UnsafeRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedDown<T: ~Copyable>(for type: T.Type) -> Self {
public func alignedDown<T: ~Copyable & ~Escapable>(for type: T.Type) -> Self {
let mask = UInt(Builtin.alignof(T.self)) &- 1
let bits = UInt(Builtin.ptrtoint_Word(_rawValue)) & ~mask
_debugPrecondition(bits != 0, "Overflow in pointer arithmetic")
Expand Down Expand Up @@ -1416,10 +1420,11 @@ extension UnsafeMutableRawPointer {
/// - type: The type of `value`.
@inlinable
@_alwaysEmitIntoClient
public func storeBytes<T: BitwiseCopyable>(
public func storeBytes<T: BitwiseCopyable & ~Escapable>(
of value: T, toByteOffset offset: Int = 0, as type: T.Type
) {
unsafe Builtin.storeRaw(value, (self + offset)._rawValue)
let immortalValue = unsafe _overrideLifetime(value, borrowing: ())
unsafe Builtin.storeRaw(immortalValue, (self + offset)._rawValue)
}

/// Stores the given value's bytes into raw memory at the specified offset.
Expand Down Expand Up @@ -1563,7 +1568,7 @@ extension UnsafeMutableRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedUp<T: ~Copyable>(for type: T.Type) -> Self {
public func alignedUp<T: ~Copyable & ~Escapable>(for type: T.Type) -> Self {
let mask = UInt(Builtin.alignof(T.self)) &- 1
let bits = (UInt(Builtin.ptrtoint_Word(_rawValue)) &+ mask) & ~mask
_debugPrecondition(bits != 0, "Overflow in pointer arithmetic")
Expand All @@ -1581,7 +1586,7 @@ extension UnsafeMutableRawPointer {
/// - Returns: a pointer properly aligned to store a value of type `T`.
@inlinable
@_alwaysEmitIntoClient
public func alignedDown<T: ~Copyable>(for type: T.Type) -> Self {
public func alignedDown<T: ~Copyable & ~Escapable>(for type: T.Type) -> Self {
let mask = UInt(Builtin.alignof(T.self)) &- 1
let bits = UInt(Builtin.ptrtoint_Word(_rawValue)) & ~mask
_debugPrecondition(bits != 0, "Overflow in pointer arithmetic")
Expand Down
93 changes: 93 additions & 0 deletions test/SILOptimizer/lifetime_dependence/rawpointer_span.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// RUN: %target-swift-frontend -primary-file %s -parse-as-library -emit-sil \
// RUN: -o /dev/null \
// RUN: -verify \
// RUN: -sil-verify-all \
// RUN: -module-name test \
// RUN: -define-availability "Span 0.1:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999" \
// RUN: -strict-memory-safety \
// RUN: -enable-experimental-feature Lifetimes

// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Lifetimes

@safe
@_silgen_name("getRawPointer")
func getRawPointer() -> UnsafeRawPointer

@safe
@_silgen_name("getMutRawPointer")
func getMutRawPointer() -> UnsafeMutableRawPointer

func useSpan(_: RawSpan) {}

//===----------------------------------------------------------------------===//
// raw pointer .load()
//===----------------------------------------------------------------------===//

@available(Span 0.1, *)
@_lifetime(immortal)
func badLoad() -> RawSpan {
let p = getRawPointer()
return unsafe p.load(as: RawSpan.self) // expected-error{{lifetime-dependent value escapes its scope}}
// expected-note@-2{{it depends on the lifetime of variable 'p'}}
// expected-note@-2{{this use causes the lifetime-dependent value to escape}}
}

@available(Span 0.1, *)
@_lifetime(borrow p)
func goodLoad(p: UnsafeRawPointer) -> RawSpan {
unsafe useSpan(p.load(as: RawSpan.self))
return unsafe p.load(as: RawSpan.self)
}

//===----------------------------------------------------------------------===//
// raw pointer .loadUnaligned()
//
// TODO: test non-BitwiseCopyable loadUnaligned
//===----------------------------------------------------------------------===//

@available(Span 0.1, *)
@_lifetime(immortal)
func badBitwiseLoadUnaligned() -> RawSpan {
let p = getRawPointer()
return unsafe p.loadUnaligned(as: RawSpan.self) // expected-error{{lifetime-dependent value escapes its scope}}
// expected-note@-2{{it depends on the lifetime of variable 'p'}}
// expected-note@-2{{this use causes the lifetime-dependent value to escape}}
}

@available(Span 0.1, *)
@_lifetime(borrow p)
func goodBitwiseLoadUnaligned(p: UnsafeRawPointer) -> RawSpan {
unsafe useSpan(p.loadUnaligned(as: RawSpan.self))
return unsafe p.loadUnaligned(as: RawSpan.self)
}

/* TODO: support loadUnaligned<T: ~BitwiseCopyable>
@_lifetime(immortal)
func badGenericLoadUnaligned<T: ~Escapable>(p: UnsafeRawPointer, _: T.Type) -> T {
let p = getRawPointer()
return unsafe p.loadUnaligned(as: T.self) // ERROR
}

@_lifetime(borrow p)
func goodGenericLoadUnaligned<T: ~Escapable>(p: UnsafeRawPointer, _: T.Type) -> T {
return unsafe p.loadUnaligned(as: T.self) // OK
}
*/

//===----------------------------------------------------------------------===//
// raw pointer .storeBytes()
//===----------------------------------------------------------------------===//

@available(Span 0.1, *)
func storeSpan(span: RawSpan) {
let p = getMutRawPointer()
unsafe p.storeBytes(of: span, as: RawSpan.self)
}

/* TODO: support storeBytes<T: ~BitwiseCopyable>
func storeGeneric<T: ~Escapable>(value: T) {
let p = getMutRawPointer()
unsafe p.storeBytes(of: value, as: T.self)
}
*/
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ Func UnsafePointer.deallocate() has generic signature change from <Pointee> to <
Func UnsafeRawBufferPointer.bindMemory(to:) has generic signature change from <T> to <T where T : ~Copyable>
Func UnsafeRawPointer.assumingMemoryBound(to:) has generic signature change from <T> to <T where T : ~Copyable>
Func UnsafeRawPointer.bindMemory(to:capacity:) has generic signature change from <T> to <T where T : ~Copyable>
Func UnsafeRawPointer.load(fromByteOffset:as:) has generic signature change from <T> to <T where T : ~Escapable>
Func swap(_:_:) has generic signature change from <T> to <T where T : ~Copyable>
Func withExtendedLifetime(_:_:) has parameter 0 changing from Default to Shared
Func withUnsafeBytes(of:_:) has generic signature change from <T, Result> to <T, E, Result where E : Swift.Error, T : ~Copyable, Result : ~Copyable>
Expand Down
3 changes: 3 additions & 0 deletions test/api-digester/stability-stdlib-abi-without-asserts.test
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,9 @@ Func UnsafeRawPointer.assumingMemoryBound(to:) is now with @_preInverseGenerics
Func UnsafeRawPointer.bindMemory(to:capacity:) has generic signature change from <T> to <T where T : ~Copyable>
Func UnsafeRawPointer.bindMemory(to:capacity:) has mangled name changing from 'Swift.UnsafeRawPointer.bindMemory<A>(to: A.Type, capacity: Swift.Int) -> Swift.UnsafePointer<A>' to 'Swift.UnsafeRawPointer.bindMemory<A where A: ~Swift.Copyable>(to: A.Type, capacity: Swift.Int) -> Swift.UnsafePointer<A>'
Func UnsafeRawPointer.bindMemory(to:capacity:) is now with @_preInverseGenerics
Func UnsafeRawPointer.load(fromByteOffset:as:) has generic signature change from <T> to <T where T : ~Escapable>
Func UnsafeRawPointer.load(fromByteOffset:as:) has mangled name changing from 'Swift.UnsafeRawPointer.load<A>(fromByteOffset: Swift.Int, as: A.Type) -> A' to 'Swift.UnsafeRawPointer.load<A where A: ~Swift.Escapable>(fromByteOffset: Swift.Int, as: A.Type) -> A'
Func UnsafeRawPointer.load(fromByteOffset:as:) is now with @_preInverseGenerics
Func _fixLifetime(_:) has generic signature change from <T> to <T where T : ~Copyable, T : ~Escapable>
Func _fixLifetime(_:) has mangled name changing from 'Swift._fixLifetime<A>(A) -> ()' to 'Swift._fixLifetime<A where A: ~Swift.Copyable, A: ~Swift.Escapable>(A) -> ()'
Func _fixLifetime(_:) has parameter 0 changing from Default to Shared
Expand Down