diff --git a/stdlib/public/core/TemporaryAllocation.swift b/stdlib/public/core/TemporaryAllocation.swift index 960eec28492f6..b1e0dfbe5b35f 100644 --- a/stdlib/public/core/TemporaryAllocation.swift +++ b/stdlib/public/core/TemporaryAllocation.swift @@ -141,14 +141,14 @@ internal func _withUnsafeTemporaryAllocation< // Builtin.stackDealloc() will end up blowing it away (and the verifier will // notice and complain.) let result: R - + #if compiler(>=5.5) && $BuiltinStackAlloc let stackAddress = Builtin.stackAlloc( capacity._builtinWordValue, MemoryLayout.stride._builtinWordValue, alignment._builtinWordValue ) - + // The multiple calls to Builtin.stackDealloc() are because defer { } produces // a child function at the SIL layer and that conflicts with the verifier's // idea of a stack allocation's lifetime. @@ -269,6 +269,25 @@ public func withUnsafeTemporaryAllocation( return try result.get() } +@available(SwiftCompatibilitySpan 5.0, *) +@_alwaysEmitIntoClient @_transparent +public func withTemporaryAllocation( + of type: T.Type, + capacity: Int, + _ body: (inout OutputSpan) throws(E) -> R +) throws(E) -> R where T : ~Copyable, R : ~Copyable { + try withUnsafeTemporaryAllocation(of: type, capacity: capacity) { (buffer) throws(E) in + var span = OutputSpan(buffer: buffer, initializedCount: 0) + defer { + let initializedCount = span.finalize(for: buffer) + span = OutputSpan() + buffer.extracting(...alignment - 1 + expectEqual(pointerBits & alignmentMask, 0) + initializedCount = 0 + } + } +} + // MARK: Typed throws enum HomeworkError: Error, Equatable { case dogAteIt @@ -172,4 +229,15 @@ TemporaryAllocationTestSuite.test("typedAllocationWithThrow") { } } +TemporaryAllocationTestSuite.test("spanWithThrow") { + do throws(HomeworkError) { + try withTemporaryAllocation(of: Int.self, capacity: 1) { (span) throws(HomeworkError) -> Void in + throw HomeworkError.forgot + } + fatalError("did not throw!?!") + } catch { + expectEqual(error, .forgot) + } +} + runAllTests()