Auto merge of - Nemo157:pinned-generators, r=Zoxc

Use pinning for generators to make trait safe

I'm unsure whether there needs to be any changes to the actual generator transform. Tests are passing so the fact that `Pin<&mut T>` is fundamentally the same as `&mut T` seems to allow it to still work, but maybe there's something subtle here that could go wrong.

This is specified in [RFC 2349 § Immovable generators](https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md#immovable-generators) (although, since that RFC it has become safe to create an immovable generator, and instead it's unsafe to resume any generator; with these changes both are now safe and instead the unsafety is moved to creating a `Pin<&mut [static generator]>` which there are safe APIs for).

CC 
This commit is contained in:
bors 2019-01-28 14:12:15 +00:00
commit d8a0dd7ae8
56 changed files with 395 additions and 170 deletions

@ -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();
}
```

@ -873,13 +873,22 @@ 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))
}
}
#[unstable(feature = "generator_trait", issue = "43122")]
impl<G: ?Sized + Generator> Generator for Pin<Box<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())
}
}

@ -627,6 +627,7 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
/// [`Pin`]: ../pin/struct.Pin.html
/// [`pin module`]: ../../std/pin/index.html
#[stable(feature = "pin", since = "1.33.0")]
#[cfg_attr(not(stage0), lang = "unpin")]
pub auto trait Unpin {}
/// A marker type which does not implement `Unpin`.

@ -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))
}
}

@ -117,6 +117,7 @@ use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};
// implementations, are allowed because they all only use `&P`, so they cannot move
// the value behind `pointer`.
#[stable(feature = "pin", since = "1.33.0")]
#[cfg_attr(not(stage0), lang = "pin")]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, Ord)]

@ -299,6 +299,8 @@ language_item_table! {
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;
UnpinTraitLangItem, "unpin", unpin_trait, Target::Trait;
PinTypeLangItem, "pin", pin_type, Target::Struct;
EqTraitLangItem, "eq", eq_trait, Target::Trait;
PartialOrdTraitLangItem, "partial_ord", partial_ord_trait, Target::Trait;

@ -2017,6 +2017,24 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// the auto impl might apply, we don't know
candidates.ambiguous = true;
}
ty::Generator(_, _, movability)
if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
{
match movability {
hir::GeneratorMovability::Static => {
// Immovable generators are never `Unpin`, so
// suppress the normal auto-impl candidate for it.
}
hir::GeneratorMovability::Movable => {
// Movable generators are always `Unpin`, so add an
// unconditional builtin candidate.
candidates.vec.push(BuiltinCandidate {
has_nested: false,
});
}
}
}
_ => candidates.vec.push(AutoImplCandidate(def_id.clone())),
}
}

@ -76,6 +76,11 @@ impl<'a, 'tcx> Instance<'tcx> {
let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
let pin_did = tcx.lang_items().pin_type().unwrap();
let pin_adt_ref = tcx.adt_def(pin_did);
let pin_substs = tcx.intern_substs(&[env_ty.into()]);
let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
sig.map_bound(|sig| {
let state_did = tcx.lang_items().gen_state().unwrap();
let state_adt_ref = tcx.adt_def(state_did);

@ -586,10 +586,17 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
return;
}
let pin_did = tcx.lang_items().pin_type();
// Or is it the closure environment?
let (closure_layout, env_ref) = match arg.layout.ty.sty {
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
ty::Adt(def, substs) if Some(def.did) == pin_did => {
match substs.type_at(0).sty {
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
_ => (arg.layout, false),
}
}
_ => (arg.layout, false)
};

@ -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>.

@ -113,6 +113,33 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
}
}
struct PinArgVisitor<'tcx> {
ref_gen_ty: Ty<'tcx>,
}
impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
fn visit_local(&mut self,
local: &mut Local,
_: PlaceContext<'tcx>,
_: Location) {
assert_ne!(*local, self_arg());
}
fn visit_place(&mut self,
place: &mut Place<'tcx>,
context: PlaceContext<'tcx>,
location: Location) {
if *place == Place::Local(self_arg()) {
*place = Place::Projection(Box::new(Projection {
base: place.clone(),
elem: ProjectionElem::Field(Field::new(0), self.ref_gen_ty),
}));
} else {
self.super_place(place, context, location);
}
}
}
fn self_arg() -> Local {
Local::new(1)
}
@ -286,6 +313,23 @@ fn make_generator_state_argument_indirect<'a, 'tcx>(
DerefArgVisitor.visit_mir(mir);
}
fn make_generator_state_argument_pinned<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &mut Mir<'tcx>) {
let ref_gen_ty = mir.local_decls.raw[1].ty;
let pin_did = tcx.lang_items().pin_type().unwrap();
let pin_adt_ref = tcx.adt_def(pin_did);
let substs = tcx.intern_substs(&[ref_gen_ty.into()]);
let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
// Replace the by ref generator argument
mir.local_decls.raw[1].ty = pin_ref_gen_ty;
// Add the Pin field access to accesses of the generator state
PinArgVisitor { ref_gen_ty }.visit_mir(mir);
}
fn replace_result_variable<'tcx>(
ret_ty: Ty<'tcx>,
mir: &mut Mir<'tcx>,
@ -741,6 +785,7 @@ fn create_generator_resume_function<'a, 'tcx>(
insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable);
make_generator_state_argument_indirect(tcx, def_id, mir);
make_generator_state_argument_pinned(tcx, mir);
no_landing_pads(tcx, mir);

@ -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),
})

@ -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() {()}

@ -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();
}
}

@ -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: 'static>(t: T) -> Box<Generator<Yield = T, Return = ()> + Unpin> {
Box::new(|| {
yield t;
})

@ -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);
}

@ -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);

@ -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);

@ -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(()));
}

@ -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

@ -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();
}

@ -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;
}

@ -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);
});
}

@ -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);

@ -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());
}

@ -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));
}

@ -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(_) => {}
}

@ -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),
}

@ -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(()));
}

@ -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();
}

@ -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),
}

@ -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

@ -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
};

@ -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

@ -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

@ -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
}

@ -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

@ -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`

@ -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`

@ -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

@ -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

@ -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

@ -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

@ -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
}

@ -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>

@ -0,0 +1,15 @@
#![feature(generators)]
// normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin"
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
}

@ -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`.

@ -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

@ -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() { }

@ -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

@ -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() { }

@ -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;
| ^^

@ -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

@ -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() { }

@ -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

@ -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
}
}
}