Skip to content

Commit fe1fd2e

Browse files
authored
[stdlib] fix UnsafePointer.withMemoryRebound(to:capacity:) argument type. (#4908)
SE-0107 states that UnsafePointer.withMemoryRebound(to:capacity:) should produce a const UnsafePointer, but the implementation that I committed in Whitney produces an UnsafeMutablePointer. As a result Swift 3 accepts code, that we would like to reject: func takesUInt(_: UnsafeMutablePointer<UInt>) {} func takesConstUInt(_: UnsafePointer<UInt>) {} func foo(p: UnsafePointer<Int>) { p.withMemoryRebound(to: UInt.self, capacity: 1) { takesUInt($0) // <========= implicitly converts to a mutable pointer takesConstUInt($0) } } We would like to reject this in favor of: func takesUInt(_: UnsafeMutablePointer<UInt>) {} func takesConstUInt(_: UnsafePointer<UInt>) {} func foo(p: UnsafePointer<Int>) { p.withMemoryRebound(to: UInt.self, capacity: 1) { takesUInt(UnsafeMutablePointer(mutating: $0)) takesConstUInt($0) } } This looks to me like an experimental change accidentally creeped onto my branch and it was hard to spot in .gyb code. I needed to write the unit test in terms of UnsafeMutablePointer in order to use expectType, so didn't catch this. rdar://28409842 UnsafePointer.withMemoryRebound(to:capacity:) incorrectly produces a mutable pointer argument
1 parent bca63b4 commit fe1fd2e

File tree

2 files changed

+10
-6
lines changed

2 files changed

+10
-6
lines changed

stdlib/public/core/UnsafePointer.swift.gyb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,13 @@ public struct ${Self}<Pointee>
369369
/// - Precondition: The memory `self..<self + count * MemoryLayout<T>.stride`
370370
/// is bound to `Pointee`.
371371
public func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int,
372-
_ body: (UnsafeMutablePointer<T>) throws -> Result
372+
_ body: (${Self}<T>) throws -> Result
373373
) rethrows -> Result {
374374
Builtin.bindMemory(_rawValue, count._builtinWordValue, T.self)
375375
defer {
376376
Builtin.bindMemory(_rawValue, count._builtinWordValue, Pointee.self)
377377
}
378-
return try body(UnsafeMutablePointer<T>(_rawValue))
378+
return try body(${Self}<T>(_rawValue))
379379
}
380380

381381
/// Accesses the pointee at `self + i`.

test/1_stdlib/UnsafePointer.swift.gyb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,16 @@ ${SelfName}TestSuite.test("Comparable") {
463463
% for SelfName in ['UnsafePointer', 'UnsafeMutablePointer']:
464464

465465
${SelfName}TestSuite.test("withMemoryRebound") {
466-
let mutablePtr = UnsafeMutablePointer<Int>.allocate(capacity: 4)
467-
let ptrI = ${SelfName}<Int>(mutablePtr)
466+
let mutablePtrI = UnsafeMutablePointer<Int>.allocate(capacity: 4)
467+
defer { mutablePtrI.deallocate(capacity: 4) }
468+
let ptrI = ${SelfName}<Int>(mutablePtrI)
468469
ptrI.withMemoryRebound(to: UInt.self, capacity: 4) {
469-
expectType(UInt.self, &$0.pointee)
470+
// Make sure the closure argument isa $SelfName
471+
var ptrU: ${SelfName}<UInt> = $0
472+
// and that the element type is UInt.
473+
var mutablePtrU = UnsafeMutablePointer(mutating: ptrU)
474+
expectType(UInt.self, &mutablePtrU.pointee)
470475
}
471-
mutablePtr.deallocate(capacity: 4)
472476
}
473477

474478
% end

0 commit comments

Comments
 (0)