-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Use pinning for generators to make trait safe #55704
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
Changes from all commits
a3fdee9
730b18b
0c20396
be39893
e7d6675
c4bf5f9
a21c95f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,9 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {} | |
impl<T: Generator<Yield = ()>> Future for GenFuture<T> { | ||
type Output = T::Return; | ||
fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> { | ||
set_task_waker(lw, || match unsafe { Pin::get_unchecked_mut(self).0.resume() } { | ||
// Safe because we're !Unpin + !Drop mapping to a ?Unpin value | ||
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; | ||
set_task_waker(lw, || match gen.resume() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @withoutboats Did you look at this? |
||
GeneratorState::Yielded(()) => Poll::Pending, | ||
GeneratorState::Complete(x) => Poll::Ready(x), | ||
}) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// min-lldb-version: 310 | ||
|
||
// compile-flags:-g | ||
|
||
// === GDB TESTS =================================================================================== | ||
|
||
// gdb-command:run | ||
// gdb-command:print a | ||
// gdb-check:$1 = 5 | ||
|
||
// === LLDB TESTS ================================================================================== | ||
|
||
// lldb-command:run | ||
// lldb-command:print a | ||
// lldbg-check:(int) $0 = 5 | ||
// lldbr-check:(int) a = 5 | ||
|
||
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait, pin)] | ||
#![omit_gdb_pretty_printer_section] | ||
|
||
use std::ops::Generator; | ||
use std::pin::Pin; | ||
|
||
fn main() { | ||
let mut a = 5; | ||
let mut b = || { | ||
yield; | ||
_zzz(); // #break | ||
a = 6; | ||
}; | ||
Pin::new(&mut b).resume(); | ||
Pin::new(&mut b).resume(); | ||
_zzz(); // #break | ||
} | ||
|
||
fn _zzz() {()} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// run-pass | ||
|
||
#![feature(generators, generator_trait)] | ||
|
||
use std::marker::{PhantomPinned, Unpin}; | ||
|
||
fn assert_unpin<G: Unpin>(_: G) { | ||
} | ||
|
||
fn main() { | ||
// Even though this generator holds a `PhantomPinned` in its environment, it | ||
// remains `Unpin`. | ||
assert_unpin(|| { | ||
let pinned = PhantomPinned; | ||
yield; | ||
drop(pinned); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// run-pass | ||
|
||
#![feature(generators, generator_trait)] | ||
|
||
use std::ops::Generator; | ||
|
||
fn assert_generator<G: Generator>(_: G) { | ||
} | ||
|
||
fn main() { | ||
assert_generator(static || yield); | ||
assert_generator(Box::pin(static || yield)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
#![feature(generators, generator_trait)] | ||
|
||
use std::pin::Pin; | ||
use std::ops::{Generator, GeneratorState}; | ||
|
||
fn main() { | ||
|
@@ -11,8 +12,9 @@ fn main() { | |
yield; | ||
assert_eq!(b as *const _, &a as *const _); | ||
}; | ||
unsafe { | ||
assert_eq!(generator.resume(), GeneratorState::Yielded(())); | ||
assert_eq!(generator.resume(), GeneratorState::Complete(())); | ||
} | ||
// Safety: We shadow the original generator variable so have no safe API to | ||
// move it after this point. | ||
let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this use unsafe code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constructing a I can add a note about why this is safe (same reason as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a note on the safety here. |
||
assert_eq!(generator.as_mut().resume(), GeneratorState::Yielded(())); | ||
assert_eq!(generator.as_mut().resume(), GeneratorState::Complete(())); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
#![feature(generators, generator_trait)] | ||
|
||
use std::ops::Generator; | ||
use std::pin::Pin; | ||
|
||
fn main() { | ||
let s = String::from("foo"); | ||
let mut gen = move || { | ||
//~^ ERROR the size for values of type | ||
yield s[..]; | ||
}; | ||
unsafe { gen.resume(); } | ||
Pin::new(&mut gen).resume(); | ||
//~^ ERROR the size for values of type | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#![feature(generators)] | ||
|
||
// normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have not been able to figure out why travis shows a different path for this compared to the two machines with rustc I've been able to test on. I attempted to trace through where the diagnostics get the path from, and as far as I can tell everything should be deterministic. The path chosen appears to come from the Parse/declaration order is also consistent with the failures in https://travis-ci.org/rust-lang/rust/jobs/451369080, that test commit forced the child order while constructing This will also become moot soon as #55766 is proposing to remove the |
||
|
||
use std::marker::Unpin; | ||
|
||
fn assert_unpin<T: Unpin>(_: T) { | ||
} | ||
|
||
fn main() { | ||
let mut generator = static || { | ||
yield; | ||
}; | ||
assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied | ||
--> $DIR/static-not-unpin.rs:14:5 | ||
| | ||
LL | assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied | ||
| ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` | ||
| | ||
note: required by `assert_unpin` | ||
--> $DIR/static-not-unpin.rs:7:1 | ||
| | ||
LL | fn assert_unpin<T: Unpin>(_: T) { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0277`. |
Uh oh!
There was an error while loading. Please reload this page.