AssertUnwindSafe interacts poorly with 2021 capture rules

std::panic::AssertUnwindSafe is a tuple type that can be used to pass arbitrary values across unwind boundaries. Its docs note that it's useful for working with std::panic::catch_unwind. Naively destructuring the closure passed into catch_unwind results in a relatively inscrutable error about a non-UnwindSafe type crossing an unwind boundary (playground example).

The simplest solution would be to give AssertUnwindSafe an into_inner() method to use instead of destructuring or point access. Another solution would be to privilege the type so that the newer capture rules don't apply to it.

I've always been wrapping the closure itself in AssertUnwindSafe rather than individual upvars, which doesn't have this problem.

Although obscure, this also works.

        let AssertUnwindSafe(value) = { unwind_safe };

I'd rather see UnwindSafe have its teeth pulled than have its machinery become magical. It already doesn't carry its weight.

5 Likes

This is a common problem though for newtypes, not just AssertUnwindSafe. For instance if you define a UnsafeAssertSend wrapper to share raw pointers with other threads, the 2021 closure capture rules will "helpfully" still pass the inner raw pointer instead of passing the wrapping struct. I have code (admittedly mostly tests) that is littered with let ptr = ptr; to trick the capture rules into capturing the entire value rather than just the field.

I think overall for the code I wrote, the 2021 capture rules are a net negative unfortunately. :confused:

A pattern I've seen is to have _ = (cap, tures); at the start of a closure to get specific names captured by complete value when they otherwise wouldn't be.

I've met this problem, but I don't think the capture rules are net negative. Many times they helped me. I think they are overall more positive (to me).