Skip to content

Commit 2c9cde1

Browse files
committed
[stdlib] fix UnsafePointer.withMemoryRebound(to:capacity:) argument type.
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 88741f9 commit 2c9cde1

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
@@ -373,13 +373,13 @@ public struct ${Self}<Pointee>
373373
/// - Precondition: The memory `self..<self + count * MemoryLayout<T>.stride`
374374
/// is bound to `Pointee`.
375375
public func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int,
376-
_ body: (UnsafeMutablePointer<T>) throws -> Result
376+
_ body: (${Self}<T>) throws -> Result
377377
) rethrows -> Result {
378378
Builtin.bindMemory(_rawValue, count._builtinWordValue, T.self)
379379
defer {
380380
Builtin.bindMemory(_rawValue, count._builtinWordValue, Pointee.self)
381381
}
382-
return try body(UnsafeMutablePointer<T>(_rawValue))
382+
return try body(${Self}<T>(_rawValue))
383383
}
384384

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

test/stdlib/UnsafePointer.swift.gyb

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

459459
${SelfName}TestSuite.test("withMemoryRebound") {
460-
let mutablePtr = UnsafeMutablePointer<Int>.allocate(capacity: 4)
461-
let ptrI = ${SelfName}<Int>(mutablePtr)
460+
let mutablePtrI = UnsafeMutablePointer<Int>.allocate(capacity: 4)
461+
defer { mutablePtrI.deallocate(capacity: 4) }
462+
let ptrI = ${SelfName}<Int>(mutablePtrI)
462463
ptrI.withMemoryRebound(to: UInt.self, capacity: 4) {
463-
expectType(UInt.self, &$0.pointee)
464+
// Make sure the closure argument isa $SelfName
465+
var ptrU: ${SelfName}<UInt> = $0
466+
// and that the element type is UInt.
467+
var mutablePtrU = UnsafeMutablePointer(mutating: ptrU)
468+
expectType(UInt.self, &mutablePtrU.pointee)
464469
}
465-
mutablePtr.deallocate(capacity: 4)
466470
}
467471

468472
% end

0 commit comments

Comments
 (0)