Rollup merge of #30513 - alexcrichton:assert-is-safe, r=aturon

Types like `&AssertRecoverSafe<T>` and `Rc<AssertRecoverSafe<T>>` were
mistakenly not considered recover safe, but the point of the assertion wrapper
is that it indeed is! This was caused by an interaction between the
`RecoverSafe` and `NoUnsafeCell` marker traits, and this is updated by adding an
impl of the `NoUnsafeCell` marker trait for `AssertRecoverSafe` to ensure that
it never interacts with the other negative impls of `RecoverSafe`.

cc #30510
This commit is contained in:
Manish Goregaokar 2015-12-25 16:54:30 +05:30
commit 91440adbed
2 changed files with 24 additions and 16 deletions

View File

@ -101,8 +101,11 @@ pub use panicking::{take_handler, set_handler, PanicInfo, Location};
across a recover boundary"] across a recover boundary"]
pub trait RecoverSafe {} pub trait RecoverSafe {}
/// A marker trait representing types which do not contain an `UnsafeCell` by /// A marker trait representing types where a shared reference is considered
/// value internally. /// recover safe.
///
/// This trait is namely not implemented by `UnsafeCell`, the root of all
/// interior mutability.
/// ///
/// This is a "helper marker trait" used to provide impl blocks for the /// This is a "helper marker trait" used to provide impl blocks for the
/// `RecoverSafe` trait, for more information see that documentation. /// `RecoverSafe` trait, for more information see that documentation.
@ -110,7 +113,7 @@ pub trait RecoverSafe {}
#[rustc_on_unimplemented = "the type {Self} contains interior mutability \ #[rustc_on_unimplemented = "the type {Self} contains interior mutability \
and a reference may not be safely transferrable \ and a reference may not be safely transferrable \
across a recover boundary"] across a recover boundary"]
pub trait NoUnsafeCell {} pub trait RefRecoverSafe {}
/// A simple wrapper around a type to assert that it is panic safe. /// A simple wrapper around a type to assert that it is panic safe.
/// ///
@ -159,11 +162,11 @@ pub struct AssertRecoverSafe<T>(T);
// * Our custom AssertRecoverSafe wrapper is indeed recover safe // * Our custom AssertRecoverSafe wrapper is indeed recover safe
impl RecoverSafe for .. {} impl RecoverSafe for .. {}
impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {} impl<'a, T: ?Sized> !RecoverSafe for &'a mut T {}
impl<'a, T: NoUnsafeCell + ?Sized> RecoverSafe for &'a T {} impl<'a, T: RefRecoverSafe + ?Sized> RecoverSafe for &'a T {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *const T {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *const T {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for *mut T {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for *mut T {}
impl<T: RecoverSafe> RecoverSafe for Unique<T> {} impl<T: RecoverSafe> RecoverSafe for Unique<T> {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Shared<T> {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Shared<T> {}
impl<T: ?Sized> RecoverSafe for Mutex<T> {} impl<T: ?Sized> RecoverSafe for Mutex<T> {}
impl<T: ?Sized> RecoverSafe for RwLock<T> {} impl<T: ?Sized> RecoverSafe for RwLock<T> {}
impl<T> RecoverSafe for AssertRecoverSafe<T> {} impl<T> RecoverSafe for AssertRecoverSafe<T> {}
@ -171,15 +174,16 @@ impl<T> RecoverSafe for AssertRecoverSafe<T> {}
// not covered via the Shared impl above b/c the inner contents use // 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 // Cell/AtomicUsize, but the usage here is recover safe so we can lift the
// impl up one level to Arc/Rc itself // impl up one level to Arc/Rc itself
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Rc<T> {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Rc<T> {}
impl<T: NoUnsafeCell + ?Sized> RecoverSafe for Arc<T> {} impl<T: RefRecoverSafe + ?Sized> RecoverSafe for Arc<T> {}
// Pretty simple implementations for the `NoUnsafeCell` marker trait, basically // Pretty simple implementations for the `RefRecoverSafe` marker trait,
// just saying that this is a marker trait and `UnsafeCell` is the only thing // basically just saying that this is a marker trait and `UnsafeCell` is the
// which doesn't implement it (which then transitively applies to everything // only thing which doesn't implement it (which then transitively applies to
// else. // everything else.
impl NoUnsafeCell for .. {} impl RefRecoverSafe for .. {}
impl<T: ?Sized> !NoUnsafeCell for UnsafeCell<T> {} impl<T: ?Sized> !RefRecoverSafe for UnsafeCell<T> {}
impl<T> RefRecoverSafe for AssertRecoverSafe<T> {}
impl<T> AssertRecoverSafe<T> { impl<T> AssertRecoverSafe<T> {
/// Creates a new `AssertRecoverSafe` wrapper around the provided type. /// Creates a new `AssertRecoverSafe` wrapper around the provided type.

View File

@ -11,7 +11,7 @@
#![allow(dead_code)] #![allow(dead_code)]
#![feature(recover)] #![feature(recover)]
use std::panic::RecoverSafe; use std::panic::{RecoverSafe, AssertRecoverSafe};
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::{Mutex, RwLock, Arc}; use std::sync::{Mutex, RwLock, Arc};
use std::rc::Rc; use std::rc::Rc;
@ -47,5 +47,9 @@ fn main() {
assert::<Box<T>>(); assert::<Box<T>>();
assert::<Vec<T>>(); assert::<Vec<T>>();
assert::<RefCell<T>>(); assert::<RefCell<T>>();
assert::<AssertRecoverSafe<T>>();
assert::<&AssertRecoverSafe<T>>();
assert::<Rc<AssertRecoverSafe<T>>>();
assert::<Arc<AssertRecoverSafe<T>>>();
} }
} }