i didn’t think this would compile, but it does:
import Atomics
extension HTTP
{
struct TimeCop:~Copyable, Sendable
{
let epoch:UnsafeAtomic<UInt>
init()
{
self.epoch = .create(0)
}
deinit
{
self.epoch.destroy()
}
}
}
let cop:HTTP.TimeCop = .init()
async
let _:Void =
{
try await cop.start(interval: .milliseconds(1000))
try await connection.channel.close()
}()
capturing this thing in a closure will end badly.
double free or corruption (fasttop)
the problem is that you can’t capture the noncopyable type in an escaping closure, and it needs to take it as a borrowing parameter:
async
let _:Void =
{
(cop:borrowing HTTP.TimeCop) in
try await cop.start(interval: .milliseconds(1000))
try await connection.channel.close()
} (cop)
but why on earth did the capturing one compile in the first place?
2 Likes
jrose
(Jordan Rose)
2
Nice catch! Does it reproduce in a function body? It wouldn’t surprise me if this was a bug in top-level code handling. (My guess is it’s expecting to be able to move the value into the closure, but it fails to.)
it is in a function scope, i undented it to make it more readable for the forums.
it raises the expected error if i'm explicit about the capture with a [cop] in.
jrose
(Jordan Rose)
4
See, that should be fine because captures of locals capture the variable, not the value. The value should still end up being destroyed exactly once.
2 Likes
i got this down to a minimal reproducer which i filed as a bug here:
4 Likes