Change generator trait to use pinning

This commit is contained in:
Wim Looman 2018-10-04 20:49:38 +02:00
parent 8611577360
commit a3fdee9a75
44 changed files with 209 additions and 170 deletions

View file

@ -29,6 +29,7 @@ A syntactical example of a generator is:
#![feature(generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn main() {
let mut generator = || {
@ -36,11 +37,11 @@ fn main() {
return "foo"
};
match unsafe { generator.resume() } {
match Pin::new(&mut generator).resume() {
GeneratorState::Yielded(1) => {}
_ => panic!("unexpected value from resume"),
}
match unsafe { generator.resume() } {
match Pin::new(&mut generator).resume() {
GeneratorState::Complete("foo") => {}
_ => panic!("unexpected value from resume"),
}
@ -60,6 +61,7 @@ prints all numbers in order:
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let mut generator = || {
@ -69,9 +71,9 @@ fn main() {
};
println!("1");
unsafe { generator.resume() };
Pin::new(&mut generator).resume();
println!("3");
unsafe { generator.resume() };
Pin::new(&mut generator).resume();
println!("5");
}
```
@ -86,13 +88,14 @@ Feedback on the design and usage is always appreciated!
The `Generator` trait in `std::ops` currently looks like:
```
# #![feature(generator_trait)]
# #![feature(arbitrary_self_types, generator_trait)]
# use std::ops::GeneratorState;
# use std::pin::Pin;
pub trait Generator {
type Yield;
type Return;
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
}
```
@ -167,6 +170,7 @@ Let's take a look at an example to see what's going on here:
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let ret = "foo";
@ -175,17 +179,18 @@ fn main() {
return ret
};
unsafe { generator.resume() };
unsafe { generator.resume() };
Pin::new(&mut generator).resume();
Pin::new(&mut generator).resume();
}
```
This generator literal will compile down to something similar to:
```rust
#![feature(generators, generator_trait)]
#![feature(arbitrary_self_types, generators, generator_trait)]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn main() {
let ret = "foo";
@ -200,9 +205,9 @@ fn main() {
type Yield = i32;
type Return = &'static str;
unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> {
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<i32, &'static str> {
use std::mem;
match mem::replace(self, __Generator::Done) {
match mem::replace(&mut *self, __Generator::Done) {
__Generator::Start(s) => {
*self = __Generator::Yield1(s);
GeneratorState::Yielded(1)
@ -223,8 +228,8 @@ fn main() {
__Generator::Start(ret)
};
unsafe { generator.resume() };
unsafe { generator.resume() };
Pin::new(&mut generator).resume();
Pin::new(&mut generator).resume();
}
```

View file

@ -873,13 +873,12 @@ impl<T: ?Sized> AsMut<T> for Box<T> {
impl<T: ?Sized> Unpin for Box<T> { }
#[unstable(feature = "generator_trait", issue = "43122")]
impl<T> Generator for Box<T>
where T: Generator + ?Sized
{
type Yield = T::Yield;
type Return = T::Return;
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
(**self).resume()
impl<G: ?Sized + Generator + Unpin> Generator for Box<G> {
type Yield = G::Yield;
type Return = G::Return;
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
G::resume(Pin::new(&mut *self))
}
}

View file

@ -1,3 +1,6 @@
use crate::marker::Unpin;
use crate::pin::Pin;
/// The result of a generator resumption.
///
/// This enum is returned from the `Generator::resume` method and indicates the
@ -39,6 +42,7 @@ pub enum GeneratorState<Y, R> {
/// #![feature(generators, generator_trait)]
///
/// use std::ops::{Generator, GeneratorState};
/// use std::pin::Pin;
///
/// fn main() {
/// let mut generator = || {
@ -46,11 +50,11 @@ pub enum GeneratorState<Y, R> {
/// return "foo"
/// };
///
/// match unsafe { generator.resume() } {
/// match Pin::new(&mut generator).resume() {
/// GeneratorState::Yielded(1) => {}
/// _ => panic!("unexpected return from resume"),
/// }
/// match unsafe { generator.resume() } {
/// match Pin::new(&mut generator).resume() {
/// GeneratorState::Complete("foo") => {}
/// _ => panic!("unexpected return from resume"),
/// }
@ -88,10 +92,6 @@ pub trait Generator {
/// generator will continue executing until it either yields or returns, at
/// which point this function will return.
///
/// The function is unsafe because it can be used on an immovable generator.
/// After such a call, the immovable generator must not move again, but
/// this is not enforced by the compiler.
///
/// # Return value
///
/// The `GeneratorState` enum returned from this function indicates what
@ -110,16 +110,25 @@ pub trait Generator {
/// been returned previously. While generator literals in the language are
/// guaranteed to panic on resuming after `Complete`, this is not guaranteed
/// for all implementations of the `Generator` trait.
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
}
#[unstable(feature = "generator_trait", issue = "43122")]
impl<T> Generator for &mut T
where T: Generator + ?Sized
{
type Yield = T::Yield;
type Return = T::Return;
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
(**self).resume()
impl<G: ?Sized + Generator> Generator for Pin<&mut G> {
type Yield = G::Yield;
type Return = G::Return;
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
G::resume((*self).as_mut())
}
}
#[unstable(feature = "generator_trait", issue = "43122")]
impl<G: ?Sized + Generator + Unpin> Generator for &mut G {
type Yield = G::Yield;
type Return = G::Return;
fn resume(mut self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return> {
G::resume(Pin::new(&mut *self))
}
}

View file

@ -2119,14 +2119,15 @@ This error occurs because a borrow in a generator persists across a
yield point.
```compile_fail,E0626
# #![feature(generators, generator_trait)]
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
# use std::pin::Pin;
let mut b = || {
let a = &String::new(); // <-- This borrow...
yield (); // ...is still in scope here, when the yield occurs.
println!("{}", a);
};
unsafe { b.resume() };
Pin::new(&mut b).resume();
```
At present, it is not permitted to have a yield that occurs while a
@ -2137,14 +2138,15 @@ resolve the previous example by removing the borrow and just storing
the integer by value:
```
# #![feature(generators, generator_trait)]
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
# use std::pin::Pin;
let mut b = || {
let a = 3;
yield ();
println!("{}", a);
};
unsafe { b.resume() };
Pin::new(&mut b).resume();
```
This is a very simple case, of course. In more complex cases, we may
@ -2154,37 +2156,40 @@ in those cases, something like the `Rc` or `Arc` types may be useful.
This error also frequently arises with iteration:
```compile_fail,E0626
# #![feature(generators, generator_trait)]
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
# use std::pin::Pin;
let mut b = || {
let v = vec![1,2,3];
for &x in &v { // <-- borrow of `v` is still in scope...
yield x; // ...when this yield occurs.
}
};
unsafe { b.resume() };
Pin::new(&mut b).resume();
```
Such cases can sometimes be resolved by iterating "by value" (or using
`into_iter()`) to avoid borrowing:
```
# #![feature(generators, generator_trait)]
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
# use std::pin::Pin;
let mut b = || {
let v = vec![1,2,3];
for x in v { // <-- Take ownership of the values instead!
yield x; // <-- Now yield is OK.
}
};
unsafe { b.resume() };
Pin::new(&mut b).resume();
```
If taking ownership is not an option, using indices can work too:
```
# #![feature(generators, generator_trait)]
# #![feature(generators, generator_trait, pin)]
# use std::ops::Generator;
# use std::pin::Pin;
let mut b = || {
let v = vec![1,2,3];
let len = v.len(); // (*)
@ -2193,7 +2198,7 @@ let mut b = || {
yield x; // <-- Now yield is OK.
}
};
unsafe { b.resume() };
Pin::new(&mut b).resume();
// (*) -- Unfortunately, these temporaries are currently required.
// See <https://github.com/rust-lang/rust/issues/43122>.

View file

@ -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() {
GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x),
})

View file

@ -12,6 +12,7 @@
use std::cell::{Cell, RefCell};
use std::ops::Generator;
use std::panic;
use std::pin::Pin;
use std::usize;
struct InjectedFailure;
@ -172,7 +173,7 @@ fn generator(a: &Allocator, run_count: usize) {
);
};
for _ in 0..run_count {
unsafe { gen.resume(); }
Pin::new(&mut gen).resume();
}
}

View file

@ -1,5 +1,6 @@
#![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::Generator;
pub fn foo() -> impl Generator<Yield = (), Return = ()> {
@ -10,7 +11,7 @@ pub fn foo() -> impl Generator<Yield = (), Return = ()> {
}
}
pub fn bar<T: 'static>(t: T) -> Box<Generator<Yield = T, Return = ()>> {
pub fn bar<T: Unpin + 'static>(t: T) -> Box<Generator<Yield = T, Return = ()> + Unpin> {
Box::new(|| {
yield t;
})

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0);
@ -34,9 +35,9 @@ fn t1() {
};
let n = A.load(Ordering::SeqCst);
unsafe { a.resume() };
Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1);
unsafe { a.resume() };
Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1);
}
@ -50,8 +51,8 @@ fn t2() {
};
let n = A.load(Ordering::SeqCst);
unsafe { a.resume() };
Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n);
unsafe { a.resume() };
Pin::new(&mut a).resume();
assert_eq!(A.load(Ordering::SeqCst), n + 1);
}

View file

@ -2,13 +2,15 @@
#![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
fn finish<T>(mut amt: usize, mut t: T) -> T::Return
where T: Generator<Yield = ()>
where T: Generator<Yield = ()> + Unpin,
{
loop {
match unsafe { t.resume() } {
match Pin::new(&mut t).resume() {
GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
GeneratorState::Complete(ret) => {
assert_eq!(amt, 0);

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0);
@ -29,7 +30,7 @@ fn t1() {
};
let n = A.load(Ordering::SeqCst);
drop(unsafe { foo.resume() });
drop(Pin::new(&mut foo).resume());
assert_eq!(A.load(Ordering::SeqCst), n);
drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1);
@ -42,7 +43,7 @@ fn t2() {
};
let n = A.load(Ordering::SeqCst);
drop(unsafe { foo.resume() });
drop(Pin::new(&mut foo).resume());
assert_eq!(A.load(Ordering::SeqCst), n + 1);
drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1);

View file

@ -3,6 +3,7 @@
#![feature(generators, generator_trait)]
use std::ops::{ Generator, GeneratorState };
use std::pin::Pin;
fn foo(_: &str) -> String {
String::new()
@ -27,8 +28,6 @@ fn bar2(baz: String) -> impl Generator<Yield = String, Return = ()> {
}
fn main() {
unsafe {
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new()));
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
}
assert_eq!(Pin::new(&mut bar(String::new())).resume(), GeneratorState::Yielded(String::new()));
assert_eq!(Pin::new(&mut bar2(String::new())).resume(), GeneratorState::Complete(()));
}

View file

@ -2,24 +2,26 @@
#![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
struct W<T>(T);
// This impl isn't safe in general, but the generator used in this test is movable
// so it won't cause problems.
impl<T: Generator<Return = ()>> Iterator for W<T> {
impl<T: Generator<Return = ()> + Unpin> Iterator for W<T> {
type Item = T::Yield;
fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.0.resume() } {
match Pin::new(&mut self.0).resume() {
GeneratorState::Complete(..) => None,
GeneratorState::Yielded(v) => Some(v),
}
}
}
fn test() -> impl Generator<Return=(), Yield=u8> {
fn test() -> impl Generator<Return=(), Yield=u8> + Unpin {
|| {
for i in 1..6 {
yield i

View file

@ -3,11 +3,12 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let b = |_| 3;
let mut a = || {
b(yield);
};
unsafe { a.resume() };
Pin::new(&mut a).resume();
}

View file

@ -1,10 +1,9 @@
// run-pass
#![feature(generators)]
#![feature(generator_trait)]
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::ops::GeneratorState;
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn main() {
let _generator = || {
@ -12,7 +11,7 @@ fn main() {
yield 2;
};
match unsafe { sub_generator.resume() } {
match Pin::new(&mut sub_generator).resume() {
GeneratorState::Yielded(x) => {
yield x;
}

View file

@ -6,6 +6,7 @@
use std::ops::Generator;
use std::panic;
use std::pin::Pin;
use std::sync::atomic::{AtomicUsize, Ordering};
static A: AtomicUsize = AtomicUsize::new(0);
@ -34,7 +35,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 0);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() }
Pin::new(&mut foo).resume()
}));
assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1);
@ -49,7 +50,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 1);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() }
Pin::new(&mut foo).resume()
}));
assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1);

View file

@ -5,6 +5,7 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
use std::panic;
fn main() {
@ -16,13 +17,13 @@ fn main() {
};
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() }
Pin::new(&mut foo).resume()
}));
assert!(res.is_err());
for _ in 0..10 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
unsafe { foo.resume() }
Pin::new(&mut foo).resume()
}));
assert!(res.is_err());
}

View file

@ -5,6 +5,7 @@
#![feature(generators, generator_trait)]
use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
use std::panic;
fn main() {
@ -15,12 +16,12 @@ fn main() {
yield;
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
match panic::catch_unwind(move || unsafe { foo.resume() }) {
match panic::catch_unwind(move || Pin::new(&mut foo).resume()) {
Ok(_) => panic!("generator successfully resumed"),
Err(_) => {}
}

View file

@ -6,6 +6,7 @@
#![feature(generators, generator_trait)]
use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
use std::thread;
#[test]
@ -16,7 +17,7 @@ fn simple() {
}
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -32,7 +33,7 @@ fn return_capture() {
a
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -44,11 +45,11 @@ fn simple_yield() {
yield;
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -61,11 +62,11 @@ fn yield_capture() {
yield b;
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -78,11 +79,11 @@ fn simple_yield_value() {
return String::from("foo")
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "bar" => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -96,11 +97,11 @@ fn return_after_yield() {
return a
};
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -148,11 +149,11 @@ fn send_and_sync() {
fn send_over_threads() {
let mut foo = || { yield };
thread::spawn(move || {
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -161,11 +162,11 @@ fn send_over_threads() {
let a = String::from("a");
let mut foo = || { yield a };
thread::spawn(move || {
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(ref s) if *s == "a" => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}

View file

@ -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) };
assert_eq!(generator.as_mut().resume(), GeneratorState::Yielded(()));
assert_eq!(generator.as_mut().resume(), GeneratorState::Complete(()));
}

View file

@ -7,7 +7,8 @@
extern crate xcrate_reachable as foo;
use std::ops::Generator;
use std::pin::Pin;
fn main() {
unsafe { foo::foo().resume(); }
Pin::new(&mut foo::foo()).resume();
}

View file

@ -7,22 +7,23 @@
extern crate xcrate;
use std::ops::{GeneratorState, Generator};
use std::pin::Pin;
fn main() {
let mut foo = xcrate::foo();
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
let mut foo = xcrate::bar(3);
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Yielded(3) => {}
s => panic!("bad state: {:?}", s),
}
match unsafe { foo.resume() } {
match Pin::new(&mut foo).resume() {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}

View file

@ -1,12 +1,12 @@
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:8:29
--> $DIR/borrowing.rs:9:33
|
LL | unsafe { (|| yield &a).resume() }
| -----------^-
| || |
| || borrowed value does not live long enough
| |value captured here by generator
| a temporary with access to the borrow is created here ...
LL | Pin::new(&mut || yield &a).resume()
| ----------^
| | |
| | borrowed value does not live long enough
| value captured here by generator
| a temporary with access to the borrow is created here ...
LL | //~^ ERROR: `a` does not live long enough
LL | };
| -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for generator
@ -16,7 +16,7 @@ LL | };
= note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:15:20
--> $DIR/borrowing.rs:16:20
|
LL | let _b = {
| -- borrow later stored here

View file

@ -1,11 +1,12 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let _b = {
let a = 3;
unsafe { (|| yield &a).resume() }
Pin::new(&mut || yield &a).resume()
//~^ ERROR: `a` does not live long enough
};

View file

@ -1,10 +1,10 @@
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:8:29
--> $DIR/borrowing.rs:9:33
|
LL | unsafe { (|| yield &a).resume() }
| -- ^ borrowed value does not live long enough
| |
| capture occurs here
LL | Pin::new(&mut || yield &a).resume()
| -- ^ borrowed value does not live long enough
| |
| capture occurs here
LL | //~^ ERROR: `a` does not live long enough
LL | };
| - borrowed value only lives until here
@ -13,7 +13,7 @@ LL | }
| - borrowed value needs to live until here
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:15:20
--> $DIR/borrowing.rs:16:20
|
LL | || {
| -- capture occurs here

View file

@ -1,5 +1,5 @@
error[E0597]: `*cell` does not live long enough
--> $DIR/dropck.rs:9:40
--> $DIR/dropck.rs:10:40
|
LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
| ^^^^ borrowed value does not live long enough
@ -13,7 +13,7 @@ LL | }
= note: values in a scope are dropped in the opposite order they are defined
error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:14:18
--> $DIR/dropck.rs:15:18
|
LL | gen = || {
| -- value captured here by generator

View file

@ -2,6 +2,7 @@
use std::cell::RefCell;
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let (mut gen, cell);
@ -14,6 +15,6 @@ fn main() {
let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
yield;
};
unsafe { gen.resume(); }
Pin::new(&mut gen).resume();
// drops the RefCell and then the Ref, leading to use-after-free
}

View file

@ -1,5 +1,5 @@
error[E0597]: `*cell` does not live long enough
--> $DIR/dropck.rs:9:40
--> $DIR/dropck.rs:10:40
|
LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
| ^^^^ borrowed value does not live long enough
@ -10,7 +10,7 @@ LL | }
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:14:18
--> $DIR/dropck.rs:15:18
|
LL | gen = || {
| -- capture occurs here

View file

@ -1,5 +1,5 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:15:51
--> $DIR/generator-region-requirements.rs:16:51
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`

View file

@ -1,5 +1,5 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/generator-region-requirements.rs:15:51
--> $DIR/generator-region-requirements.rs:16:51
|
LL | fn dangle(x: &mut i32) -> &'static mut i32 {
| -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`

View file

@ -4,6 +4,7 @@
#![feature(generators, generator_trait)]
#![cfg_attr(nll, feature(nll))]
use std::ops::{Generator, GeneratorState};
use std::pin::Pin;
fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || {
@ -11,7 +12,7 @@ fn dangle(x: &mut i32) -> &'static mut i32 {
x
};
loop {
match unsafe { g.resume() } {
match Pin::new(&mut g).resume() {
GeneratorState::Complete(c) => return c,
//[nll]~^ ERROR explicit lifetime required
//[ast]~^^ ERROR explicit lifetime required

View file

@ -1,5 +1,5 @@
error[E0521]: borrowed data escapes outside of generator
--> $DIR/ref-escapes-but-not-over-yield.rs:14:9
--> $DIR/ref-escapes-but-not-over-yield.rs:11:9
|
LL | let mut a = &3;
| ----- `a` is declared here, outside of the generator body

View file

@ -1,7 +1,4 @@
#![feature(generators, generator_trait)]
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
#![feature(generators)]
fn foo(x: &i32) {
// In this case, a reference to `b` escapes the generator, but not

View file

@ -1,5 +1,5 @@
error[E0597]: `b` does not live long enough
--> $DIR/ref-escapes-but-not-over-yield.rs:14:14
--> $DIR/ref-escapes-but-not-over-yield.rs:11:14
|
LL | a = &b;
| ^ borrowed value does not live long enough

View file

@ -1,6 +1,7 @@
#![feature(generators, generator_trait)]
use std::ops::Generator;
use std::pin::Pin;
fn main() {
let s = String::from("foo");
@ -8,6 +9,6 @@ fn main() {
//~^ ERROR the size for values of type
yield s[..];
};
unsafe { gen.resume(); }
Pin::new(&mut gen).resume();
//~^ ERROR the size for values of type
}

View file

@ -1,5 +1,5 @@
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/sized-yield.rs:7:26
--> $DIR/sized-yield.rs:8:26
|
LL | let mut gen = move || {
| __________________________^
@ -13,10 +13,10 @@ LL | | };
= note: the yield type of a generator must have a statically known size
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/sized-yield.rs:11:17
--> $DIR/sized-yield.rs:12:23
|
LL | unsafe { gen.resume(); }
| ^^^^^^ doesn't have a size known at compile-time
LL | Pin::new(&mut gen).resume();
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields
--> $DIR/yield-while-iterating.rs:12:18
--> $DIR/yield-while-iterating.rs:13:18
|
LL | for p in &x { //~ ERROR
| ^^
@ -7,7 +7,7 @@ LL | yield();
| ------- possible yield occurs here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/yield-while-iterating.rs:57:20
--> $DIR/yield-while-iterating.rs:58:20
|
LL | let mut b = || {
| -- mutable borrow occurs here
@ -16,8 +16,8 @@ LL | for p in &mut x {
...
LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here
LL | b.resume();
| - mutable borrow later used here
LL | Pin::new(&mut b).resume();
| ------ mutable borrow later used here
error: aborting due to 2 previous errors

View file

@ -2,6 +2,7 @@
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
use std::pin::Pin;
fn yield_during_iter_owned_data(x: Vec<i32>) {
// The generator owns `x`, so we error out when yielding with a
@ -33,7 +34,7 @@ fn yield_during_iter_borrowed_slice_2() {
println!("{:?}", x);
}
unsafe fn yield_during_iter_borrowed_slice_3() {
fn yield_during_iter_borrowed_slice_3() {
// OK to take a mutable ref to `x` and yield
// up pointers from it:
let mut x = vec![22_i32];
@ -42,10 +43,10 @@ unsafe fn yield_during_iter_borrowed_slice_3() {
yield p;
}
};
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn yield_during_iter_borrowed_slice_4() {
fn yield_during_iter_borrowed_slice_4() {
// ...but not OK to do that while reading
// from `x` too
let mut x = vec![22_i32];
@ -55,10 +56,10 @@ unsafe fn yield_during_iter_borrowed_slice_4() {
}
};
println!("{}", x[0]); //~ ERROR
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn yield_during_range_iter() {
fn yield_during_range_iter() {
// Should be OK.
let mut b = || {
let v = vec![1,2,3];
@ -68,7 +69,7 @@ unsafe fn yield_during_range_iter() {
yield x;
}
};
b.resume();
Pin::new(&mut b).resume();
}
fn main() { }

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields
--> $DIR/yield-while-iterating.rs:12:19
--> $DIR/yield-while-iterating.rs:13:19
|
LL | for p in &x { //~ ERROR
| ^
@ -7,7 +7,7 @@ LL | yield();
| ------- possible yield occurs here
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/yield-while-iterating.rs:57:20
--> $DIR/yield-while-iterating.rs:58:20
|
LL | let mut b = || {
| -- mutable borrow occurs here
@ -16,7 +16,7 @@ LL | for p in &mut x {
...
LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here
LL | b.resume();
LL | Pin::new(&mut b).resume();
LL | }
| - mutable borrow ends here

View file

@ -4,8 +4,9 @@
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
use std::pin::Pin;
unsafe fn borrow_local_inline() {
fn borrow_local_inline() {
// Not OK to yield with a borrow of a temporary.
//
// (This error occurs because the region shows up in the type of
@ -17,10 +18,10 @@ unsafe fn borrow_local_inline() {
yield();
println!("{}", a);
};
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn borrow_local_inline_done() {
fn borrow_local_inline_done() {
// No error here -- `a` is not in scope at the point of `yield`.
let mut b = move || {
{
@ -28,10 +29,10 @@ unsafe fn borrow_local_inline_done() {
}
yield();
};
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn borrow_local() {
fn borrow_local() {
// Not OK to yield with a borrow of a temporary.
//
// (This error occurs because the region shows up in the type of
@ -46,7 +47,7 @@ unsafe fn borrow_local() {
println!("{}", b);
}
};
b.resume();
Pin::new(&mut b).resume();
}
fn main() { }

View file

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:14:22
--> $DIR/yield-while-local-borrowed.rs:15:22
|
LL | let a = &mut 3;
| ^
@ -8,7 +8,7 @@ LL | yield();
| ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:42:22
--> $DIR/yield-while-local-borrowed.rs:43:22
|
LL | let b = &a;
| ^
@ -17,7 +17,7 @@ LL | yield();
| ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:14:17
--> $DIR/yield-while-local-borrowed.rs:15:17
|
LL | let a = &mut 3;
| ^^^^^^
@ -26,7 +26,7 @@ LL | yield();
| ------- possible yield occurs here
error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:42:21
--> $DIR/yield-while-local-borrowed.rs:43:21
|
LL | let b = &a;
| ^^

View file

@ -1,5 +1,5 @@
error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
--> $DIR/yield-while-ref-reborrowed.rs:35:20
--> $DIR/yield-while-ref-reborrowed.rs:36:20
|
LL | let mut b = || {
| -- generator construction occurs here
@ -8,8 +8,8 @@ LL | let a = &mut *x;
...
LL | println!("{}", x); //~ ERROR
| ^ second borrow occurs here
LL | b.resume();
| - first borrow later used here
LL | Pin::new(&mut b).resume();
| ------ first borrow later used here
error: aborting due to previous error

View file

@ -2,8 +2,9 @@
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
use std::pin::Pin;
unsafe fn reborrow_shared_ref(x: &i32) {
fn reborrow_shared_ref(x: &i32) {
// This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator.
let mut b = move || {
@ -11,10 +12,10 @@ unsafe fn reborrow_shared_ref(x: &i32) {
yield();
println!("{}", a);
};
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn reborrow_mutable_ref(x: &mut i32) {
fn reborrow_mutable_ref(x: &mut i32) {
// This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator.
let mut b = move || {
@ -22,10 +23,10 @@ unsafe fn reborrow_mutable_ref(x: &mut i32) {
yield();
println!("{}", a);
};
b.resume();
Pin::new(&mut b).resume();
}
unsafe fn reborrow_mutable_ref_2(x: &mut i32) {
fn reborrow_mutable_ref_2(x: &mut i32) {
// ...but not OK to go on using `x`.
let mut b = || {
let a = &mut *x;
@ -33,7 +34,7 @@ unsafe fn reborrow_mutable_ref_2(x: &mut i32) {
println!("{}", a);
};
println!("{}", x); //~ ERROR
b.resume();
Pin::new(&mut b).resume();
}
fn main() { }

View file

@ -1,5 +1,5 @@
error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
--> $DIR/yield-while-ref-reborrowed.rs:35:20
--> $DIR/yield-while-ref-reborrowed.rs:36:20
|
LL | let mut b = || {
| -- closure construction occurs here
@ -8,7 +8,7 @@ LL | let a = &mut *x;
...
LL | println!("{}", x); //~ ERROR
| ^ borrow occurs here
LL | b.resume();
LL | Pin::new(&mut b).resume();
LL | }
| - borrow from closure ends here

View file

@ -1,23 +1,23 @@
#![allow(unused_mut)]
#![feature(generators, generator_trait)]
use std::marker::Unpin;
use std::ops::Generator;
use std::ops::GeneratorState::Yielded;
use std::pin::Pin;
pub struct GenIter<G>(G);
impl <G> Iterator for GenIter<G>
where
G: Generator,
G: Generator + Unpin,
{
type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
match self.0.resume() {
Yielded(y) => Some(y),
_ => None
}
match Pin::new(&mut self.0).resume() {
Yielded(y) => Some(y),
_ => None
}
}
}