Skip to content
Merged
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
31 changes: 18 additions & 13 deletions src/doc/unstable-book/src/language-features/generators.md
Original file line number Diff line number Diff line change
@@ -29,18 +29,19 @@ 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 = || {
yield 1;
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();
}
```

23 changes: 16 additions & 7 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
@@ -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())
}
}

1 change: 1 addition & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
@@ -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`.
37 changes: 23 additions & 14 deletions src/libcore/ops/generator.rs
Original file line number Diff line number Diff line change
@@ -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,18 +42,19 @@ pub enum GeneratorState<Y, R> {
/// #![feature(generators, generator_trait)]
///
/// use std::ops::{Generator, GeneratorState};
/// use std::pin::Pin;
///
/// fn main() {
/// let mut generator = || {
/// yield 1;
/// 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<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<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 + 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))
}
}
1 change: 1 addition & 0 deletions src/libcore/pin.rs
Original file line number Diff line number Diff line change
@@ -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)]
2 changes: 2 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 18 additions & 0 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -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())),
}
}
5 changes: 5 additions & 0 deletions src/librustc/ty/instance.rs
Original file line number Diff line number Diff line change
@@ -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);
7 changes: 7 additions & 0 deletions src/librustc_codegen_ssa/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -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)
};

25 changes: 15 additions & 10 deletions src/librustc_mir/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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>.
45 changes: 45 additions & 0 deletions src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
@@ -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);

4 changes: 3 additions & 1 deletion src/libstd/future.rs
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() {
Copy link
Contributor

Choose a reason for hiding this comment

The 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),
})
36 changes: 36 additions & 0 deletions src/test/debuginfo/generators.rs
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() {()}
3 changes: 2 additions & 1 deletion src/test/run-pass/drop/dynamic-drop.rs
Original file line number Diff line number Diff line change
@@ -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();
}
}

3 changes: 2 additions & 1 deletion src/test/run-pass/generator/auxiliary/xcrate.rs
Original file line number Diff line number Diff line change
@@ -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;
})
9 changes: 5 additions & 4 deletions src/test/run-pass/generator/conditional-drop.rs
Original file line number Diff line number Diff line change
@@ -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);
}
6 changes: 4 additions & 2 deletions src/test/run-pass/generator/control-flow.rs
Original file line number Diff line number Diff line change
@@ -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);
5 changes: 3 additions & 2 deletions src/test/run-pass/generator/drop-env.rs
Original file line number Diff line number Diff line change
@@ -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);
7 changes: 3 additions & 4 deletions src/test/run-pass/generator/issue-44197.rs
Original file line number Diff line number Diff line change
@@ -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(()));
}
8 changes: 5 additions & 3 deletions src/test/run-pass/generator/iterator-count.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 1 deletion src/test/run-pass/generator/live-upvar-across-yield.rs
Original file line number Diff line number Diff line change
@@ -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();
}
9 changes: 4 additions & 5 deletions src/test/run-pass/generator/nested_generators.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// 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 = || {
let mut sub_generator = || {
yield 2;
};

match unsafe { sub_generator.resume() } {
match Pin::new(&mut sub_generator).resume() {
GeneratorState::Yielded(x) => {
yield x;
}
18 changes: 18 additions & 0 deletions src/test/run-pass/generator/non-static-is-unpin.rs
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);
});
}
5 changes: 3 additions & 2 deletions src/test/run-pass/generator/panic-drops.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 2 deletions src/test/run-pass/generator/panic-safe.rs
Original file line number Diff line number Diff line change
@@ -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());
}
13 changes: 13 additions & 0 deletions src/test/run-pass/generator/pin-box-generator.rs
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));
}
5 changes: 3 additions & 2 deletions src/test/run-pass/generator/resume-after-return.rs
Original file line number Diff line number Diff line change
@@ -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(_) => {}
}
29 changes: 15 additions & 14 deletions src/test/run-pass/generator/smoke.rs
Original file line number Diff line number Diff line change
@@ -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),
}
10 changes: 6 additions & 4 deletions src/test/run-pass/generator/static-generators.rs
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) };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this use unsafe code?

Copy link
Member Author

@Nemo157 Nemo157 Nov 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructing a Pin to a reference to !Unpin value is unsafe. There is a safe macro-based solution to do so on the stack, but it's not included in std. I could use a Pin<Box> here instead safely, but I thought better to just keep it on the stack.

I can add a note about why this is safe (same reason as pin_mut! is safe, it shadows the owning binding so the value cannot be moved after this line).

Copy link
Member Author

Choose a reason for hiding this comment

The 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(()));
}
3 changes: 2 additions & 1 deletion src/test/run-pass/generator/xcrate-reachable.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 3 deletions src/test/run-pass/generator/xcrate.rs
Original file line number Diff line number Diff line change
@@ -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),
}
16 changes: 8 additions & 8 deletions src/test/ui/generator/borrowing.nll.stderr
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/test/ui/generator/borrowing.rs
Original file line number Diff line number Diff line change
@@ -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
};

12 changes: 6 additions & 6 deletions src/test/ui/generator/borrowing.stderr
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions src/test/ui/generator/dropck.nll.stderr
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/test/ui/generator/dropck.rs
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 2 additions & 2 deletions src/test/ui/generator/dropck.stderr
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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`
Original file line number Diff line number Diff line change
@@ -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`
3 changes: 2 additions & 1 deletion src/test/ui/generator/generator-region-requirements.rs
Original file line number Diff line number Diff line change
@@ -4,14 +4,15 @@
#![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 = || {
yield;
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
Original file line number Diff line number Diff line change
@@ -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
5 changes: 1 addition & 4 deletions src/test/ui/generator/ref-escapes-but-not-over-yield.rs
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/test/ui/generator/sized-yield.rs
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
}
8 changes: 4 additions & 4 deletions src/test/ui/generator/sized-yield.stderr
Original file line number Diff line number Diff line change
@@ -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>
15 changes: 15 additions & 0 deletions src/test/ui/generator/static-not-unpin.rs
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"
Copy link
Member Author

Choose a reason for hiding this comment

The 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 visible_parent_map built here, this is done as a BFS, and should be deterministic within a single crate. Following the order of an items children back from here through the different representations all the way to libsyntax there doesn't appear to be anything that should change the order, then in libsyntax an items children come out in parse order. std re-exports the core::marker module before the core::pin module, so the path chosen to be displayed should be std::marker::Pin.

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 visible_parent_map to be sorted by name. All the failures were swapping paths that were declared earlier with paths declared later but alphabetically sorted earlier.

This will also become moot soon as #55766 is proposing to remove the std::pin::Unpin re-export (although, it does plan to add it to the prelude which will then become the preferred path).


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
}
15 changes: 15 additions & 0 deletions src/test/ui/generator/static-not-unpin.stderr
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`.
8 changes: 4 additions & 4 deletions src/test/ui/generator/yield-while-iterating.nll.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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
| ^^
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

13 changes: 7 additions & 6 deletions src/test/ui/generator/yield-while-iterating.rs
Original file line number Diff line number Diff line change
@@ -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() { }
6 changes: 3 additions & 3 deletions src/test/ui/generator/yield-while-iterating.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
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
| ^
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

13 changes: 7 additions & 6 deletions src/test/ui/generator/yield-while-local-borrowed.rs
Original file line number Diff line number Diff line change
@@ -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,21 +18,21 @@ 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 || {
{
let a = &mut 3;
}
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() { }
8 changes: 4 additions & 4 deletions src/test/ui/generator/yield-while-local-borrowed.stderr
Original file line number Diff line number Diff line change
@@ -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;
| ^^
6 changes: 3 additions & 3 deletions src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr
Original file line number Diff line number Diff line change
@@ -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

13 changes: 7 additions & 6 deletions src/test/ui/generator/yield-while-ref-reborrowed.rs
Original file line number Diff line number Diff line change
@@ -2,38 +2,39 @@

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 || {
let a = &*x;
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 || {
let a = &mut *x;
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;
yield();
println!("{}", a);
};
println!("{}", x); //~ ERROR
b.resume();
Pin::new(&mut b).resume();
}

fn main() { }
4 changes: 2 additions & 2 deletions src/test/ui/generator/yield-while-ref-reborrowed.stderr
Original file line number Diff line number Diff line change
@@ -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

12 changes: 6 additions & 6 deletions src/test/ui/nll/issue-55850.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
}