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

Add a dummy lifetime to Wrapper #107

Merged
merged 1 commit into from
Sep 25, 2019
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ A crate for safe and ergonomic pin-projection.

[Documentation][docs-url]

[Examples](examples/README.md)

## Usage

Add this to your `Cargo.toml`:
Expand Down
5 changes: 3 additions & 2 deletions examples/unsafe_unpin-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ impl<T, U> Foo<T, U> {

unsafe impl<T: Unpin, U> UnsafeUnpin for Foo<T, U> {}

impl<T, U> ::core::marker::Unpin for Foo<T, U> where
::pin_project::__private::Wrapper<Self>: ::pin_project::UnsafeUnpin
#[allow(single_use_lifetimes)]
impl<'_pin, T, U> ::core::marker::Unpin for Foo<T, U> where
::pin_project::__private::Wrapper<'_pin, Self>: ::pin_project::UnsafeUnpin
{
}

Expand Down
10 changes: 5 additions & 5 deletions pin-project-internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ use utils::{Immutable, Mutable};
/// }
/// ```
///
/// Note that borrowing the field where `#[pin]` attribute is used multiple
/// times requires using [`.as_mut()`][`Pin::as_mut`] to avoid
/// consuming the `Pin`.
///
/// If you want to implement [`Unpin`] manually, you must use the `UnsafeUnpin`
/// argument to `#[pin_project]`.
///
Expand Down Expand Up @@ -167,11 +171,7 @@ use utils::{Immutable, Mutable};
/// are being used. If you implement [`UnsafeUnpin`], you must ensure that it is
/// only implemented when all pin-projected fields implement [`Unpin`].
///
/// Note that borrowing the field where `#[pin]` attribute is used multiple
/// times requires using [`.as_mut()`][`Pin::as_mut`] to avoid
/// consuming the `Pin`.
///
/// See also [`UnsafeUnpin`] trait.
/// See [`UnsafeUnpin`] trait for more details.
///
/// ### `#[pinned_drop]`
///
Expand Down
12 changes: 7 additions & 5 deletions pin-project-internal/src/pin_project/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,19 +184,21 @@ impl Context {
return TokenStream::new();
};

let mut generics = self.generics.clone();
let orig_ident = &self.orig_ident;
let mut proj_generics = self.proj_generics();
let Self { orig_ident, lifetime, .. } = self;

generics.make_where_clause().predicates.push(
proj_generics.make_where_clause().predicates.push(
syn::parse2(quote_spanned! { unsafe_unpin =>
::pin_project::__private::Wrapper<Self>: ::pin_project::UnsafeUnpin
::pin_project::__private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin
})
.unwrap(),
);

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
let ty_generics = self.generics.split_for_impl().1;

quote! {
#[allow(single_use_lifetimes)]
impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #where_clause {}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub unsafe trait UnsafeUnpin {}
#[doc(hidden)]
pub mod __private {
use super::UnsafeUnpin;
use core::pin::Pin;
use core::{marker::PhantomData, pin::Pin};

#[doc(hidden)]
pub use pin_project_internal::__PinProjectAutoImplUnpin;
Expand Down Expand Up @@ -195,8 +195,8 @@ pub mod __private {
// to making the type never implement Unpin), or provide an impl of `UnsafeUnpin`.
// It is impossible for them to provide an impl of `Unpin`
#[doc(hidden)]
pub struct Wrapper<T>(T);
pub struct Wrapper<'a, T>(T, PhantomData<&'a ()>);

#[allow(unsafe_code)]
unsafe impl<T> UnsafeUnpin for Wrapper<T> where T: UnsafeUnpin {}
unsafe impl<T> UnsafeUnpin for Wrapper<'_, T> where T: UnsafeUnpin {}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// compile-fail

// FIXME?

use pin_project::pin_project;

#[pin_project(UnsafeUnpin)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0277]: the trait bound `Foo<(), ()>: pin_project::UnsafeUnpin` is not satisfied
--> $DIR/forget-unsafe-unpin-impl.rs:17:16
--> $DIR/not-implement-unsafe-unpin.rs:15:16
|
14 | fn is_unpin<T: Unpin>() {}
12 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
17 | is_unpin::<Foo<(), ()>>(); //~ ERROR E0277
15 | is_unpin::<Foo<(), ()>>(); //~ ERROR E0277
| ^^^^^^^^^^^ the trait `pin_project::UnsafeUnpin` is not implemented for `Foo<(), ()>`
|
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<Foo<(), ()>>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Foo<(), ()>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<(), ()>`

error: aborting due to previous error
Expand Down
37 changes: 30 additions & 7 deletions tests/ui/unsafe_unpin/proper_unpin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,42 @@
use pin_project::{pin_project, UnsafeUnpin};
use std::marker::PhantomPinned;

fn is_unpin<T: Unpin>() {}

#[pin_project(UnsafeUnpin)]
struct Foo<T, U> {
pub struct Blah<T, U> {
field1: U,
#[pin]
inner: T,
other: U,
field2: T,
}

unsafe impl<T: Unpin, U> UnsafeUnpin for Foo<T, U> {}
#[allow(unsafe_code)]
unsafe impl<T: Unpin, U> UnsafeUnpin for Blah<T, U> {}

fn is_unpin<T: Unpin>() {}
#[pin_project(UnsafeUnpin)]
pub struct NotImplementUnsafUnpin {
#[pin]
field1: PhantomPinned,
}

#[pin_project(UnsafeUnpin)]
pub struct OverlappingLifetimeNames<'_pin, T, U> {
#[pin]
field1: U,
#[pin]
field2: Option<T>,
field3: &'_pin (),
}

#[allow(unsafe_code)]
unsafe impl<T: Unpin, U: Unpin> UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {}

fn foo_is_unpin() {
is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
fn unsafe_unpin() {
is_unpin::<Blah<PhantomPinned, ()>>(); //~ ERROR E0277
is_unpin::<Blah<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
is_unpin::<NotImplementUnsafUnpin>(); //~ ERROR E0277
is_unpin::<OverlappingLifetimeNames<'_, PhantomPinned, ()>>(); //~ ERROR E0277
is_unpin::<OverlappingLifetimeNames<'_, (), PhantomPinned>>(); //~ ERROR E0277
}

fn main() {}
73 changes: 65 additions & 8 deletions tests/ui/unsafe_unpin/proper_unpin.stderr
Original file line number Diff line number Diff line change
@@ -1,18 +1,75 @@
error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied
--> $DIR/proper_unpin.rs:18:5
--> $DIR/proper_unpin.rs:37:5
|
15 | fn is_unpin<T: Unpin>() {}
6 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
18 | is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
37 | is_unpin::<Blah<PhantomPinned, ()>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= help: the following implementations were found:
<std::marker::PhantomPinned as std::marker::Unpin>
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `Foo<std::marker::PhantomPinned, std::marker::PhantomPinned>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<Foo<std::marker::PhantomPinned, std::marker::PhantomPinned>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<std::marker::PhantomPinned, std::marker::PhantomPinned>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `Blah<std::marker::PhantomPinned, ()>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah<std::marker::PhantomPinned, ()>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah<std::marker::PhantomPinned, ()>`

error: aborting due to previous error
error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied
--> $DIR/proper_unpin.rs:38:5
|
6 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
38 | is_unpin::<Blah<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= help: the following implementations were found:
<std::marker::PhantomPinned as std::marker::Unpin>
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `Blah<std::marker::PhantomPinned, std::marker::PhantomPinned>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah<std::marker::PhantomPinned, std::marker::PhantomPinned>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah<std::marker::PhantomPinned, std::marker::PhantomPinned>`

error[E0277]: the trait bound `NotImplementUnsafUnpin: pin_project::UnsafeUnpin` is not satisfied
--> $DIR/proper_unpin.rs:39:16
|
6 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
39 | is_unpin::<NotImplementUnsafUnpin>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `pin_project::UnsafeUnpin` is not implemented for `NotImplementUnsafUnpin`
|
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, NotImplementUnsafUnpin>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `NotImplementUnsafUnpin`

error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied
--> $DIR/proper_unpin.rs:40:5
|
6 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
40 | is_unpin::<OverlappingLifetimeNames<'_, PhantomPinned, ()>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= help: the following implementations were found:
<std::marker::PhantomPinned as std::marker::Unpin>
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>`

error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied
--> $DIR/proper_unpin.rs:41:5
|
6 | fn is_unpin<T: Unpin>() {}
| -------- ----- required by this bound in `is_unpin`
...
41 | is_unpin::<OverlappingLifetimeNames<'_, (), PhantomPinned>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= help: the following implementations were found:
<std::marker::PhantomPinned as std::marker::Unpin>
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>`
= note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>>`
= note: required because of the requirements on the impl of `std::marker::Unpin` for `OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>`

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
6 changes: 5 additions & 1 deletion tests/ui/unstable-features/trivial_bounds-feature-gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ use std::marker::PhantomPinned;

struct Inner(PhantomPinned);

#[pin_project] //~ ERROR E0277
// As a workaround, you need to use `UnsafeUnpin`.
#[pin_project(UnsafeUnpin)] // Ok
struct Foo(#[pin] Inner);

#[pin_project] //~ ERROR E0277
struct Bar(#[pin] Inner);

fn main() {}
10 changes: 5 additions & 5 deletions tests/ui/unstable-features/trivial_bounds-feature-gate.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied in `UnpinStructFoo`
--> $DIR/trivial_bounds-feature-gate.rs:10:1
error[E0277]: the trait bound `std::marker::PhantomPinned: std::marker::Unpin` is not satisfied in `UnpinStructBar`
--> $DIR/trivial_bounds-feature-gate.rs:14:1
|
10 | #[pin_project] //~ ERROR E0277
| ^^^^^^^^^^^^^^ within `UnpinStructFoo`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
14 | #[pin_project] //~ ERROR E0277
| ^^^^^^^^^^^^^^ within `UnpinStructBar`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
|
= help: the following implementations were found:
<std::marker::PhantomPinned as std::marker::Unpin>
= note: required because it appears within the type `Inner`
= note: required because it appears within the type `UnpinStructFoo`
= note: required because it appears within the type `UnpinStructBar`
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable

Expand Down
52 changes: 41 additions & 11 deletions tests/unsafe_unpin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,51 @@
#![allow(dead_code)]

use pin_project::{pin_project, UnsafeUnpin};
use std::marker::PhantomPinned;
use std::{marker::PhantomPinned, pin::Pin};

fn is_unpin<T: Unpin>() {}

#[test]
fn unsafe_unpin() {
#[pin_project(UnsafeUnpin)]
pub struct Blah<T, U> {
field1: U,
#[pin]
field2: Option<T>,
}
#[pin_project(UnsafeUnpin)]
pub struct Blah<T, U> {
field1: U,
#[pin]
field2: T,
}

#[allow(unsafe_code)]
unsafe impl<T: Unpin, U> UnsafeUnpin for Blah<T, U> {}

#[allow(unsafe_code)]
unsafe impl<T: Unpin, U> UnsafeUnpin for Blah<T, U> {}
#[pin_project(UnsafeUnpin)]
pub struct NotImplementUnsafUnpin {
#[pin]
field1: PhantomPinned,
}

#[pin_project(UnsafeUnpin)]
pub struct OverlappingLifetimeNames<'_pin, T, U> {
#[pin]
field1: T,
field2: U,
field3: &'_pin (),
}

#[allow(unsafe_code)]
unsafe impl<T: Unpin, U> UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {}

#[test]
fn unsafe_unpin() {
is_unpin::<Blah<(), PhantomPinned>>();
is_unpin::<OverlappingLifetimeNames<'_, (), ()>>();
}

#[test]
fn test() {
let mut x = OverlappingLifetimeNames { field1: 0, field2: 1, field3: &() };
let x = Pin::new(&mut x);
let y = x.as_ref().project_ref();
let _: Pin<&u8> = y.field1;
let _: &u8 = y.field2;
let y = x.project();
let _: Pin<&mut u8> = y.field1;
let _: &mut u8 = y.field2;
}