Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work around negative_impls that allows unsound overlapping Unpin impls #357

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/enum-default-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ const _: () = {
__field0: T,
}
impl<'pin, T, U> ::pin_project::__private::Unpin for Enum<T, U> where
__Enum<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Enum<'pin, T, U>>:
::pin_project::__private::Unpin
{
}
// A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
#[doc(hidden)]
unsafe impl<'pin, T, U> ::pin_project::UnsafeUnpin for Enum<T, U> where
__Enum<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Enum<'pin, T, U>>:
::pin_project::__private::Unpin
{
}

Expand Down
11 changes: 7 additions & 4 deletions examples/not_unpin-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ const _: () = {
//
// See https://github.com/taiki-e/pin-project/issues/102#issuecomment-540472282
// for details.
#[doc(hidden)]
impl<'pin, T, U> ::pin_project::__private::Unpin for Struct<T, U> where
::pin_project::__private::Wrapper<'pin, ::pin_project::__private::PhantomPinned>:
::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<
::pin_project::__private::Wrapper<'pin, ::pin_project::__private::PhantomPinned>,
>: ::pin_project::__private::Unpin
{
}
// A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
Expand All @@ -108,8 +110,9 @@ const _: () = {
// coherence checks are run.
#[doc(hidden)]
unsafe impl<'pin, T, U> ::pin_project::UnsafeUnpin for Struct<T, U> where
::pin_project::__private::Wrapper<'pin, ::pin_project::__private::PhantomPinned>:
::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<
::pin_project::__private::Wrapper<'pin, ::pin_project::__private::PhantomPinned>,
>: ::pin_project::__private::Unpin
{
}

Expand Down
6 changes: 4 additions & 2 deletions examples/pinned_drop-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ const _: () = {
__lifetime0: &'a (),
}
impl<'pin, 'a, T> ::pin_project::__private::Unpin for Struct<'a, T> where
__Struct<'pin, 'a, T>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, 'a, T>>:
::pin_project::__private::Unpin
{
}
// A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
#[doc(hidden)]
unsafe impl<'pin, 'a, T> ::pin_project::UnsafeUnpin for Struct<'a, T> where
__Struct<'pin, 'a, T>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, 'a, T>>:
::pin_project::__private::Unpin
{
}
};
Expand Down
6 changes: 4 additions & 2 deletions examples/project_replace-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,15 @@ const _: () = {
__field0: T,
}
impl<'pin, T, U> ::pin_project::__private::Unpin for Struct<T, U> where
__Struct<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, T, U>>:
::pin_project::__private::Unpin
{
}
// A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
#[doc(hidden)]
unsafe impl<'pin, T, U> ::pin_project::UnsafeUnpin for Struct<T, U> where
__Struct<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, T, U>>:
::pin_project::__private::Unpin
{
}

Expand Down
6 changes: 4 additions & 2 deletions examples/struct-default-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ const _: () = {
__field0: T,
}
impl<'pin, T, U> ::pin_project::__private::Unpin for Struct<T, U> where
__Struct<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, T, U>>:
::pin_project::__private::Unpin
{
}
// A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
Expand All @@ -140,7 +141,8 @@ const _: () = {
// coherence checks are run.
#[doc(hidden)]
unsafe impl<'pin, T, U> ::pin_project::UnsafeUnpin for Struct<T, U> where
__Struct<'pin, T, U>: ::pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<__Struct<'pin, T, U>>:
::pin_project::__private::Unpin
{
}

Expand Down
3 changes: 2 additions & 1 deletion examples/unsafe_unpin-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ const _: () = {

// Implement `Unpin` via `UnsafeUnpin`.
impl<'pin, T, U> ::pin_project::__private::Unpin for Struct<T, U> where
::pin_project::__private::Wrapper<'pin, Self>: ::pin_project::UnsafeUnpin
::pin_project::__private::PinnedFieldsOf<::pin_project::__private::Wrapper<'pin, Self>>:
::pin_project::UnsafeUnpin
{
}

Expand Down
11 changes: 7 additions & 4 deletions pin-project-internal/src/pin_project/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,9 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {

// Make the error message highlight `UnsafeUnpin` argument.
proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span =>
_pin_project::__private::Wrapper<#lifetime, Self>: _pin_project::UnsafeUnpin
::pin_project::__private::PinnedFieldsOf<
_pin_project::__private::Wrapper<#lifetime, Self>
>: _pin_project::UnsafeUnpin
});

let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
Expand All @@ -712,9 +714,9 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
let lifetime = &cx.proj.lifetime;

proj_generics.make_where_clause().predicates.push(parse_quote! {
_pin_project::__private::Wrapper<
::pin_project::__private::PinnedFieldsOf<_pin_project::__private::Wrapper<
#lifetime, _pin_project::__private::PhantomPinned
>: _pin_project::__private::Unpin
>>: _pin_project::__private::Unpin
});

let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl();
Expand Down Expand Up @@ -793,7 +795,8 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl();

full_where_clause.predicates.push(parse_quote! {
#struct_ident #proj_ty_generics: _pin_project::__private::Unpin
::pin_project::__private::PinnedFieldsOf<#struct_ident #proj_ty_generics>:
_pin_project::__private::Unpin
});

quote! {
Expand Down
23 changes: 17 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,29 +276,42 @@ pub mod __private {
#[doc(hidden)]
#[allow(dead_code)]
pub struct Wrapper<'a, T: ?Sized>(PhantomData<&'a ()>, T);

// SAFETY: `T` implements UnsafeUnpin.
unsafe impl<T: ?Sized + UnsafeUnpin> UnsafeUnpin for Wrapper<'_, T> {}

// 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-internal`.
//
// See https://github.com/taiki-e/pin-project/pull/53 for more details.
#[doc(hidden)]
pub struct AlwaysUnpin<'a, T>(PhantomData<&'a ()>, PhantomData<T>);

impl<T> 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 @@ -316,14 +329,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
8 changes: 6 additions & 2 deletions tests/expand/default/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/default/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Struct<T, U>
where
__Struct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Struct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Struct<T, U>
where
__Struct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Struct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait StructMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/default/tuple_struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for TupleStruct<T, U>
where
__TupleStruct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__TupleStruct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for TupleStruct<T, U>
where
__TupleStruct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__TupleStruct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait TupleStructMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/multifields/enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/multifields/struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Struct<T, U>
where
__Struct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Struct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Struct<T, U>
where
__Struct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Struct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait StructMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/multifields/tuple_struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for TupleStruct<T, U>
where
__TupleStruct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__TupleStruct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for TupleStruct<T, U>
where
__TupleStruct<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__TupleStruct<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait TupleStructMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/naming/enum-all.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/naming/enum-mut.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/naming/enum-none.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
8 changes: 6 additions & 2 deletions tests/expand/naming/enum-own.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,16 @@ const _: () = {
}
impl<'pin, T, U> _pin_project::__private::Unpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
#[doc(hidden)]
unsafe impl<'pin, T, U> _pin_project::UnsafeUnpin for Enum<T, U>
where
__Enum<'pin, T, U>: _pin_project::__private::Unpin,
::pin_project::__private::PinnedFieldsOf<
__Enum<'pin, T, U>,
>: _pin_project::__private::Unpin,
{}
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds, drop_bounds)]
Expand Down
Loading