Skip to content
Merged
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
12 changes: 8 additions & 4 deletions stdlib/public/SDK/ObjectiveC/ObjectiveC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ public struct NSZone {
typealias Zone = NSZone

//===----------------------------------------------------------------------===//
// FIXME: @autoreleasepool substitute
// @autoreleasepool substitute
//===----------------------------------------------------------------------===//

@warn_unused_result
Expand All @@ -191,10 +191,14 @@ func __pushAutoreleasePool() -> OpaquePointer
@_silgen_name("_swift_objc_autoreleasePoolPop")
func __popAutoreleasePool(_ pool: OpaquePointer)

public func autoreleasepool(_ code: @noescape () -> Void) {
public func autoreleasepool<Result>(
_ body: @noescape () throws -> Result
) rethrows -> Result {
let pool = __pushAutoreleasePool()
code()
__popAutoreleasePool(pool)
defer {
__popAutoreleasePool(pool)
}
return try body()
}

//===----------------------------------------------------------------------===//
Expand Down
36 changes: 36 additions & 0 deletions test/Interpreter/SDK/autorelease.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,39 @@ print("autorelease test end")
// CHECK-NEXT: object died
// CHECK-NEXT: after call to useTemp
// CHECK-NEXT: autorelease test end

// Using an @objc class to check that errors are retained across the pool
// boundaries. A classic crash is an error created inside a pool and then
// zombied before handling it outside the pool.
@objc class Error : NSObject, ErrorProtocol {
let message: String
init(message: String) {
self.message = message
}
}

// Check that rethrow works.
func requireString(string: String?) throws -> String {
guard let string = string else {
throw Error(message: "no string")
}
print("returning \"\(string)\"")
return string
}
do {
try autoreleasepool {
try requireString(string: "ok")
try requireString(string: nil)
}
} catch let err as Error {
print("caught \"\(err.message)\"")
}
// CHECK-NEXT: returning "ok"
// CHECK-NEXT: caught "no string"

// Check that a return value can be passed back.
let result = try autoreleasepool {
return "a string"
}
print("result = \"\(result)\"")
// CHECK-NEXT: result = "a string"