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 0009800 commit f6c7504
Show file tree
Hide file tree
Showing 51 changed files with 308 additions and 120 deletions.
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

0 comments on commit f6c7504

Please sign in to comment.