Change:
Test Case 1: Test Case 2: Both produce errors like this: CC
Hm, so the first case here should work (e.g. should subvert basically everything), although the second case is correct in yielding an error (albeit not a very good one)
Is the second case not allowed then? 's documentation suggests that manually implementing it is okay to do: I figured only existed to wrap types which you couldn't yourself, but for which you can ensure their invariants are upheld across the boundary. And what about moving values into the closure? can't be unwrapped, at least not currently.
Oh wait sorry I misread your second example, I failed to notice the manual ! This is basically a case where closure captures are coming into play. The closures aren't annotated with , so outer variables are captured by-reference which means that the actual types being tested against the trait here are and . In the first case that should be handled by , but the second is legitimately indicating that it's not a recover-safe type (b/c the reference is different than the by-value). You should be able to get around this via either plus or via . Certainly an interesting interaction going on here though. One would likely expect that if isn't recover safe that would fix the problem but it's likely what you really need to do is due to the way closures largely work.
There's , why not ? Coherence?
Nah unfortunately that'd defeat the purpose of the distinction. The type is itself recover safe, it's just that's not (so the distinction need to be there)
It's unfortunate that fails due to coherence or something like that:
Hm interesting, I guess yeah you'll be forced to move the reference inside the wrapper rather than having a reference to the wrapper
Is it possible to implement then? My use case can contain and friends but I'm guaranteeing that they're unobservable in user code after recovery because I immediately re-panic after escaping the FFI stack.
I guess I can just use once it's fixed :stuckouttongue:. I see your PR has been accepted so I'll look forward to trying it on tonight's nightly. When do the buildbots fire?
Yeah currently you can implement (being renamed to ) I believe (although I can't say I've tried). For now though yeah I'd recommend just using plus closures. The PR is in but'll take a few hours at least to land.
the problem with moving at this point in time is that I call in different branches of a but I pass the same closed-over value to it; I can't do the branch in the closure because I need to do some FFI cleanup afterwards regardless of whether a panic happened or not (which also requires the closed-over value). It would help if derived and/or so I could reuse it without constructing a new value for each arm, but that would probably require some discussion because I don't know if it's safe or not. I'll probably just implement and fix the name after your PR drops. A quick check confirms that it works just fine. Thanks anyways!
Oh yeah we could totally add more traits like and to , there shouldn't be any safety concerns there.
Updating code to modern functions and traits in makes this compile, so I'm going to close.

Discussion:
across a recover boundary"] pub trait RecoverSafe {} <del> /// A marker trait representing types which do not contain an `UnsafeCell` by /// value internally. </del> <ins> /// A marker trait representing types where a shared reference is considered /// recover safe. /// /// This trait is namely not implemented by `UnsafeCell`, the root of all /// interior mutability. </ins> /// /// This is a "helper marker trait" used to provide impl blocks for the /// `RecoverSafe` trait, for more information see that documentation.

#[rustc_on_unimplemented = "the type {Self} contains interior mutability  and a reference may not be safely transferrable  across a recover boundary"] <del> pub trait NoUnsafeCell {} </del> <ins> pub trait RefRecoverSafe {} </ins> /// A simple wrapper around a type to assert that it is panic safe. ///

// * Our custom AssertRecoverSafe wrapper is indeed recover safe impl RecoverSafe for .. {} impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {} <del> impl<'a, T: NoUnsafeCell + ?Sized> RecoverSafe for &'a T {} impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *const T {} impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *mut T {} </del> <ins> impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {} </ins> impl<T: RecoverSafe> RecoverSafe for Unique<T> {} <del> impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Shared<T> {} </del> <ins> impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {} </ins> impl<T: ?Sized> RecoverSafe for Mutex<T> {} impl<T: ?Sized> RecoverSafe for RwLock<T> {} impl<T> RecoverSafe for AssertRecoverSafe<T> {}

// not covered via the Shared impl above b/c the inner contents use // Cell/AtomicUsize, but the usage here is recover safe so we can lift the // impl up one level to Arc/Rc itself <del> impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Rc<T> {} impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Arc<T> {} </del> <ins> impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {} </ins> <del> // Pretty simple implementations for the `NoUnsafeCell` marker trait, basically // just saying that this is a marker trait and `UnsafeCell` is the only thing // which doesn't implement it (which then transitively applies to everything // else. impl NoUnsafeCell for .. {} impl<T: ?Sized> !NoUnsafeCell for UnsafeCell<T> {} </del> <ins> // Pretty simple implementations for the `RefRecoverSafe` marker trait, // basically just saying that this is a marker trait and `UnsafeCell` is the // only thing which doesn't implement it (which then transitively applies to // everything else. impl RefRecoverSafe for .. {} impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {} impl<T> RefRecoverSafe for AssertRecoverSafe<T> {} </ins> impl<T> AssertRecoverSafe<T> { /// Creates a new `AssertRecoverSafe` wrapper around the provided type.

#![allow(dead_code)] #![feature(recover)] <del> use std::panic::RecoverSafe; </del> <ins> use std::panic::{RecoverSafe, AssertRecoverSafe}; </ins> use std::cell::RefCell; use std::sync::{Mutex, RwLock, Arc}; use std::rc::Rc;

assert::<Box<T>>(); assert::<Vec<T>>(); assert::<RefCell<T>>(); <ins> assert::<AssertRecoverSafe<T>>(); assert::<&AssertRecoverSafe<T>>(); assert::<Rc<AssertRecoverSafe<T>>>(); assert::<Arc<AssertRecoverSafe<T>>>(); </ins> } }