Skip to content

Commit

Permalink
Work around negative_impls that allows unsound overlapping Unpin impls
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Oct 24, 2024
1 parent 0a3bfbb commit 57d5679
Show file tree
Hide file tree
Showing 19 changed files with 105 additions and 23 deletions.
27 changes: 20 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ macro_rules! __pin_project_make_unpin_impl {
//
// See also https://github.com/taiki-e/pin-project/pull/53.
#[allow(non_snake_case)]
$vis struct __Origin <'__pin, $($impl_generics)*>
$vis struct __Origin<'__pin, $($impl_generics)*>
$(where
$($where_clause)*)?
{
Expand All @@ -1230,7 +1230,8 @@ macro_rules! __pin_project_make_unpin_impl {
}
impl <'__pin, $($impl_generics)*> $crate::__private::Unpin for $ident <$($ty_generics)*>
where
__Origin <'__pin, $($ty_generics)*>: $crate::__private::Unpin
$crate::__private::PinnedFieldsOf<__Origin<'__pin, $($ty_generics)*>>:
$crate::__private::Unpin
$(, $($where_clause)*)?
{
}
Expand Down Expand Up @@ -1674,23 +1675,37 @@ pub mod __private {
ptr,
};

// Workaround for issue on unstable negative_impls feature that allows unsound overlapping Unpin
// implementations and rustc bug that leaks unstable negative_impls into stable.
// See https://github.com/taiki-e/pin-project/issues/340#issuecomment-2432146009 for details.
#[doc(hidden)]
pub type PinnedFieldsOf<T> =
<PinnedFieldsOfHelperStruct<T> as PinnedFieldsOfHelperTrait>::Actual;
// We cannot use <Option<T> as IntoIterator>::Item or similar since we should allow ?Sized in T.
#[doc(hidden)]
pub trait PinnedFieldsOfHelperTrait {
type Actual: ?Sized;
}
#[doc(hidden)]
pub struct PinnedFieldsOfHelperStruct<T: ?Sized>(T);
impl<T: ?Sized> PinnedFieldsOfHelperTrait for PinnedFieldsOfHelperStruct<T> {
type Actual = T;
}

// This is an internal helper struct used by `pin_project!`.
#[doc(hidden)]
pub struct AlwaysUnpin<T: ?Sized>(PhantomData<T>);

impl<T: ?Sized> Unpin for AlwaysUnpin<T> {}

// This is an internal helper used to ensure a value is dropped.
#[doc(hidden)]
pub struct UnsafeDropInPlaceGuard<T: ?Sized>(*mut T);

impl<T: ?Sized> UnsafeDropInPlaceGuard<T> {
#[doc(hidden)]
pub unsafe fn new(ptr: *mut T) -> Self {
Self(ptr)
}
}

impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> {
fn drop(&mut self) {
// SAFETY: the caller of `UnsafeDropInPlaceGuard::new` must guarantee
Expand All @@ -1708,14 +1723,12 @@ pub mod __private {
target: *mut T,
value: ManuallyDrop<T>,
}

impl<T> UnsafeOverwriteGuard<T> {
#[doc(hidden)]
pub unsafe fn new(target: *mut T, value: T) -> Self {
Self { target, value: ManuallyDrop::new(value) }
}
}

impl<T> Drop for UnsafeOverwriteGuard<T> {
fn drop(&mut self) {
// SAFETY: the caller of `UnsafeOverwriteGuard::new` must guarantee
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/default/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/default/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/multifields/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/multifields/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/enum-all.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/enum-mut.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/enum-none.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/enum-ref.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/struct-all.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/struct-mut.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/struct-none.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/naming/struct-ref.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/pinned_drop/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
impl<T, U> ::pin_project_lite::__private::Drop for Enum<T, U> {
fn drop(&mut self) {
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/pinned_drop/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
impl<T, U> ::pin_project_lite::__private::Drop for Struct<T, U> {
fn drop(&mut self) {
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/pub/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/pub/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ const _: () = {
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct<T, U>
where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin,
::pin_project_lite::__private::PinnedFieldsOf<
__Origin<'__pin, T, U>,
>: ::pin_project_lite::__private::Unpin,
{}
trait MustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/pin_project/negative_impls_stable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

// https://github.com/taiki-e/pin-project/issues/340#issuecomment-2428002670

pin_project_lite::pin_project! {
struct Foo<Pinned, Unpinned> {
#[pin]
pinned: Pinned,
unpinned: Unpinned,
}
}

struct MyPhantomPinned(::core::marker::PhantomPinned);
impl Unpin for MyPhantomPinned where for<'cursed> str: Sized {}
impl Unpin for Foo<MyPhantomPinned, ()> {}

fn is_unpin<T: Unpin>() {}

fn main() {
is_unpin::<Foo<MyPhantomPinned, ()>>()
}
16 changes: 16 additions & 0 deletions tests/ui/pin_project/negative_impls_stable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0119]: conflicting implementations of trait `Unpin` for type `Foo<MyPhantomPinned, ()>`
--> tests/ui/pin_project/negative_impls_stable.rs:5:1
|
5 | / pin_project_lite::pin_project! {
6 | | struct Foo<Pinned, Unpinned> {
7 | | #[pin]
8 | | pinned: Pinned,
9 | | unpinned: Unpinned,
10 | | }
11 | | }
| |_^ conflicting implementation for `Foo<MyPhantomPinned, ()>`
...
15 | impl Unpin for Foo<MyPhantomPinned, ()> {}
| --------------------------------------- first implementation here
|
= note: this error originates in the macro `$crate::__pin_project_make_unpin_impl` which comes from the expansion of the macro `pin_project_lite::pin_project` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 57d5679

Please sign in to comment.