From 57d56797ff0dd87ce0031d47d9837383674e6147 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 24 Oct 2024 20:38:55 +0900 Subject: [PATCH] Work around negative_impls that allows unsound overlapping Unpin impls --- src/lib.rs | 27 ++++++++++++++----- tests/expand/default/enum.expanded.rs | 4 ++- tests/expand/default/struct.expanded.rs | 4 ++- tests/expand/multifields/enum.expanded.rs | 4 ++- tests/expand/multifields/struct.expanded.rs | 4 ++- tests/expand/naming/enum-all.expanded.rs | 4 ++- tests/expand/naming/enum-mut.expanded.rs | 4 ++- tests/expand/naming/enum-none.expanded.rs | 4 ++- tests/expand/naming/enum-ref.expanded.rs | 4 ++- tests/expand/naming/struct-all.expanded.rs | 4 ++- tests/expand/naming/struct-mut.expanded.rs | 4 ++- tests/expand/naming/struct-none.expanded.rs | 4 ++- tests/expand/naming/struct-ref.expanded.rs | 4 ++- tests/expand/pinned_drop/enum.expanded.rs | 4 ++- tests/expand/pinned_drop/struct.expanded.rs | 4 ++- tests/expand/pub/enum.expanded.rs | 4 ++- tests/expand/pub/struct.expanded.rs | 4 ++- tests/ui/pin_project/negative_impls_stable.rs | 21 +++++++++++++++ .../pin_project/negative_impls_stable.stderr | 16 +++++++++++ 19 files changed, 105 insertions(+), 23 deletions(-) create mode 100644 tests/ui/pin_project/negative_impls_stable.rs create mode 100644 tests/ui/pin_project/negative_impls_stable.stderr diff --git a/src/lib.rs b/src/lib.rs index bbb63e0..51c1624 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)*)? { @@ -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)*)? { } @@ -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 = + as PinnedFieldsOfHelperTrait>::Actual; + // We cannot use 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); + impl PinnedFieldsOfHelperTrait for PinnedFieldsOfHelperStruct { + type Actual = T; + } + // This is an internal helper struct used by `pin_project!`. #[doc(hidden)] pub struct AlwaysUnpin(PhantomData); - impl Unpin for AlwaysUnpin {} // This is an internal helper used to ensure a value is dropped. #[doc(hidden)] pub struct UnsafeDropInPlaceGuard(*mut T); - impl UnsafeDropInPlaceGuard { #[doc(hidden)] pub unsafe fn new(ptr: *mut T) -> Self { Self(ptr) } } - impl Drop for UnsafeDropInPlaceGuard { fn drop(&mut self) { // SAFETY: the caller of `UnsafeDropInPlaceGuard::new` must guarantee @@ -1708,14 +1723,12 @@ pub mod __private { target: *mut T, value: ManuallyDrop, } - impl UnsafeOverwriteGuard { #[doc(hidden)] pub unsafe fn new(target: *mut T, value: T) -> Self { Self { target, value: ManuallyDrop::new(value) } } } - impl Drop for UnsafeOverwriteGuard { fn drop(&mut self) { // SAFETY: the caller of `UnsafeOverwriteGuard::new` must guarantee diff --git a/tests/expand/default/enum.expanded.rs b/tests/expand/default/enum.expanded.rs index 456b8cc..b01e4a8 100644 --- a/tests/expand/default/enum.expanded.rs +++ b/tests/expand/default/enum.expanded.rs @@ -133,7 +133,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/default/struct.expanded.rs b/tests/expand/default/struct.expanded.rs index a9792e1..4c86c89 100644 --- a/tests/expand/default/struct.expanded.rs +++ b/tests/expand/default/struct.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/multifields/enum.expanded.rs b/tests/expand/multifields/enum.expanded.rs index f722a14..f65dd3e 100644 --- a/tests/expand/multifields/enum.expanded.rs +++ b/tests/expand/multifields/enum.expanded.rs @@ -79,7 +79,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/multifields/struct.expanded.rs b/tests/expand/multifields/struct.expanded.rs index 83ebefe..30716b1 100644 --- a/tests/expand/multifields/struct.expanded.rs +++ b/tests/expand/multifields/struct.expanded.rs @@ -134,7 +134,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/naming/enum-all.expanded.rs b/tests/expand/naming/enum-all.expanded.rs index 456b8cc..b01e4a8 100644 --- a/tests/expand/naming/enum-all.expanded.rs +++ b/tests/expand/naming/enum-all.expanded.rs @@ -133,7 +133,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/naming/enum-mut.expanded.rs b/tests/expand/naming/enum-mut.expanded.rs index 342588c..7143c74 100644 --- a/tests/expand/naming/enum-mut.expanded.rs +++ b/tests/expand/naming/enum-mut.expanded.rs @@ -54,7 +54,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/naming/enum-none.expanded.rs b/tests/expand/naming/enum-none.expanded.rs index fc3b3dc..b03fb6d 100644 --- a/tests/expand/naming/enum-none.expanded.rs +++ b/tests/expand/naming/enum-none.expanded.rs @@ -16,7 +16,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/naming/enum-ref.expanded.rs b/tests/expand/naming/enum-ref.expanded.rs index 5270e12..27476d2 100644 --- a/tests/expand/naming/enum-ref.expanded.rs +++ b/tests/expand/naming/enum-ref.expanded.rs @@ -54,7 +54,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/naming/struct-all.expanded.rs b/tests/expand/naming/struct-all.expanded.rs index 13c4079..e9abe0f 100644 --- a/tests/expand/naming/struct-all.expanded.rs +++ b/tests/expand/naming/struct-all.expanded.rs @@ -113,7 +113,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/naming/struct-mut.expanded.rs b/tests/expand/naming/struct-mut.expanded.rs index 9b6dae8..5655548 100644 --- a/tests/expand/naming/struct-mut.expanded.rs +++ b/tests/expand/naming/struct-mut.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/naming/struct-none.expanded.rs b/tests/expand/naming/struct-none.expanded.rs index a9792e1..4c86c89 100644 --- a/tests/expand/naming/struct-none.expanded.rs +++ b/tests/expand/naming/struct-none.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/naming/struct-ref.expanded.rs b/tests/expand/naming/struct-ref.expanded.rs index 9fea20d..5c834b6 100644 --- a/tests/expand/naming/struct-ref.expanded.rs +++ b/tests/expand/naming/struct-ref.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/expand/pinned_drop/enum.expanded.rs b/tests/expand/pinned_drop/enum.expanded.rs index ce513ea..c591a32 100644 --- a/tests/expand/pinned_drop/enum.expanded.rs +++ b/tests/expand/pinned_drop/enum.expanded.rs @@ -91,7 +91,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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 ::pin_project_lite::__private::Drop for Enum { fn drop(&mut self) { diff --git a/tests/expand/pinned_drop/struct.expanded.rs b/tests/expand/pinned_drop/struct.expanded.rs index 47f1912..366171f 100644 --- a/tests/expand/pinned_drop/struct.expanded.rs +++ b/tests/expand/pinned_drop/struct.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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 ::pin_project_lite::__private::Drop for Struct { fn drop(&mut self) { diff --git a/tests/expand/pub/enum.expanded.rs b/tests/expand/pub/enum.expanded.rs index 85c7770..eddb690 100644 --- a/tests/expand/pub/enum.expanded.rs +++ b/tests/expand/pub/enum.expanded.rs @@ -91,7 +91,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum 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)] diff --git a/tests/expand/pub/struct.expanded.rs b/tests/expand/pub/struct.expanded.rs index a06783d..7df7e3f 100644 --- a/tests/expand/pub/struct.expanded.rs +++ b/tests/expand/pub/struct.expanded.rs @@ -75,7 +75,9 @@ const _: () = { } impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct 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)] diff --git a/tests/ui/pin_project/negative_impls_stable.rs b/tests/ui/pin_project/negative_impls_stable.rs new file mode 100644 index 0000000..03cd92e --- /dev/null +++ b/tests/ui/pin_project/negative_impls_stable.rs @@ -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 { + #[pin] + pinned: Pinned, + unpinned: Unpinned, + } +} + +struct MyPhantomPinned(::core::marker::PhantomPinned); +impl Unpin for MyPhantomPinned where for<'cursed> str: Sized {} +impl Unpin for Foo {} + +fn is_unpin() {} + +fn main() { + is_unpin::>() +} diff --git a/tests/ui/pin_project/negative_impls_stable.stderr b/tests/ui/pin_project/negative_impls_stable.stderr new file mode 100644 index 0000000..3059cc7 --- /dev/null +++ b/tests/ui/pin_project/negative_impls_stable.stderr @@ -0,0 +1,16 @@ +error[E0119]: conflicting implementations of trait `Unpin` for type `Foo` + --> tests/ui/pin_project/negative_impls_stable.rs:5:1 + | +5 | / pin_project_lite::pin_project! { +6 | | struct Foo { +7 | | #[pin] +8 | | pinned: Pinned, +9 | | unpinned: Unpinned, +10 | | } +11 | | } + | |_^ conflicting implementation for `Foo` +... +15 | impl Unpin for Foo {} + | --------------------------------------- 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)