Skip to content

Commit

Permalink
Merge PinnedDrop and DropInner
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Oct 1, 2020
1 parent 4835493 commit 9ba5c56
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 62 deletions.
67 changes: 19 additions & 48 deletions src/lib.rs
Expand Up @@ -425,34 +425,17 @@ macro_rules! __pin_project_internal {
)?
{
fn drop(&mut self) {
// Safety - we're in 'drop', so we know that 'self' will
// never move again.
let pinned_self = unsafe { $crate::__private::Pin::new_unchecked(self) };
// We call `pinned_drop` only once. Since `PinnedDrop::drop`
// is an unsafe method and a private API, it is never called again in safe
// code *unless the user uses a maliciously crafted macro*.
unsafe {
$crate::__private::PinnedDrop::drop(pinned_self);
}
}
}
impl $(<
$( $generics
$(: $generics_bound)?
$(: ?$generics_unsized_bound)?
$(: $generics_lifetime_bound)?
),*
>)? $crate::__private::PinnedDrop for $self_ty
$(where
$( $where_clause_ty
$(: $where_clause_bound)?
$(: ?$where_clause_unsized_bound)?
$(: $where_clause_lifetime_bound)?
),*
)?
{
unsafe fn drop(self: $crate::__private::Pin<&mut Self>) {
trait __InnerDrop {
// Implementing `__DropInner::__drop_inner` is safe, but calling it is not safe.
// This is because destructors can be called multiple times in safe code and
// [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
//
// `__drop_inner` is defined as a safe method, but this is fine since
// `__drop_inner` is not accessible by the users and we call `__drop_inner` only
// once.
//
// Users can implement [`Drop`] safely using `pin_project!` and can drop a
// type that implements `PinnedDrop` using the [`drop`] function safely.
trait __DropInner {
fn __drop_inner(self: $crate::__private::Pin<&mut Self>);
}
impl $(<
Expand All @@ -461,7 +444,7 @@ macro_rules! __pin_project_internal {
$(: ?$generics_unsized_bound)?
$(: $generics_lifetime_bound)?
),*
>)? __InnerDrop for $self_ty
>)? __DropInner for $self_ty
$(where
$( $where_clause_ty
$(: $where_clause_bound)?
Expand All @@ -474,7 +457,13 @@ macro_rules! __pin_project_internal {
$($tt)*
}
}
__InnerDrop::__drop_inner(self);

// Safety - we're in 'drop', so we know that 'self' will
// never move again.
let pinned_self = unsafe { $crate::__private::Pin::new_unchecked(self) };
// We call `__drop_inner` only once. Since `__DropInner::__drop_inner`
// is not accessible by the users, it is never called again.
__DropInner::__drop_inner(pinned_self);
}
}
};
Expand Down Expand Up @@ -681,24 +670,6 @@ pub mod __private {
pin::Pin,
};

// Implementing `PinnedDrop::drop` is safe, but calling it is not safe.
// This is because destructors can be called multiple times in safe code and
// [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
//
// Ideally, it would be desirable to be able to forbid manual calls in
// the same way as [`Drop::drop`], but the library cannot do it. So, by using
// macros and replacing them with private traits, we prevent users from
// calling `PinnedDrop::drop`.
//
// Users can implement [`Drop`] safely using `#[pinned_drop]` and can drop a
// type that implements `PinnedDrop` using the [`drop`] function safely.
// **Do not call or implement this trait directly.**
#[doc(hidden)]
pub trait PinnedDrop {
#[doc(hidden)]
unsafe fn drop(self: Pin<&mut Self>);
}

// This is an internal helper struct used by `pin_project!`.
#[doc(hidden)]
pub struct AlwaysUnpin<T: ?Sized>(PhantomData<T>);
Expand Down
22 changes: 8 additions & 14 deletions tests/expand/tests/expand/pinned_drop-struct.expanded.rs
Expand Up @@ -4,6 +4,7 @@ struct Struct<T, U> {
pinned: T,
unpinned: U,
}
#[allow(explicit_outlives_requirements)]
#[allow(single_use_lifetimes)]
#[allow(clippy::used_underscore_binding)]
const _: () = {
Expand Down Expand Up @@ -61,29 +62,22 @@ const _: () = {
}
impl<T, U> ::pin_project_lite::__private::Drop for Struct<T, U> {
fn drop(&mut self) {
let pinned_self = unsafe { ::pin_project_lite::__private::Pin::new_unchecked(self) };
unsafe {
::pin_project_lite::__private::PinnedDrop::drop(pinned_self);
}
}
}
impl<T, U> ::pin_project_lite::__private::PinnedDrop for Struct<T, U> {
unsafe fn drop(self: ::pin_project_lite::__private::Pin<&mut Self>) {
trait __InnerDrop {
trait __DropInner {
fn __drop_inner(self: ::pin_project_lite::__private::Pin<&mut Self>);
}
impl<T, U> __InnerDrop for Struct<T, U> {
impl<T, U> __DropInner for Struct<T, U> {
fn __drop_inner(self: ::pin_project_lite::__private::Pin<&mut Self>) {
let _this = self;
}
}
__InnerDrop::__drop_inner(self);
let pinned_self = unsafe { ::pin_project_lite::__private::Pin::new_unchecked(self) };
__DropInner::__drop_inner(pinned_self);
}
}
#[deny(safe_packed_borrows)]
#[forbid(safe_packed_borrows)]
fn __assert_not_repr_packed<T, U>(this: &Struct<T, U>) {
&this.pinned;
&this.unpinned;
let _ = &this.pinned;
let _ = &this.unpinned;
}
};
fn main() {}

0 comments on commit 9ba5c56

Please sign in to comment.