diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 968534e58bd9e..426fc01a6b051 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -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; + fn resume(self: Pin<&mut Self>) -> GeneratorState; } ``` @@ -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 { + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { 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(); } ``` diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1c459f5c4250e..14a1242e3e569 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -873,13 +873,22 @@ impl AsMut for Box { impl Unpin for Box { } #[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Box - where T: Generator + ?Sized -{ - type Yield = T::Yield; - type Return = T::Return; - unsafe fn resume(&mut self) -> GeneratorState { - (**self).resume() +impl Generator for Box { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume(Pin::new(&mut *self)) + } +} + +#[unstable(feature = "generator_trait", issue = "43122")] +impl Generator for Pin> { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume((*self).as_mut()) } } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 65752ba032104..457d556e4fa6d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -627,6 +627,7 @@ unsafe impl 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`. diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 1542cd6397e78..5401fff860e9b 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -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 { /// #![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 { /// 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; + fn resume(self: Pin<&mut Self>) -> GeneratorState; +} + +#[unstable(feature = "generator_trait", issue = "43122")] +impl Generator for Pin<&mut G> { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume((*self).as_mut()) + } } #[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for &mut T - where T: Generator + ?Sized -{ - type Yield = T::Yield; - type Return = T::Return; - unsafe fn resume(&mut self) -> GeneratorState { - (**self).resume() +impl Generator for &mut G { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume(Pin::new(&mut *self)) } } diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 7c09a36d89883..56a32c928fb3d 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -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)] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c203ea96f3d64..87107f727a05d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9a0610f45dec2..6fe4a7a52be86 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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())), } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 78b6ffaa54e17..bc43fedef0f34 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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); diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 85a663dacdcc5..c7e2131eed5da 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -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) }; diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 74394165a5f84..eb72175421638 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -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 . diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index ec0c118634d0f..f5cc6a43e28b9 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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); diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 22900c3067b11..d1203be3cf011 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -33,7 +33,9 @@ impl> !Unpin for GenFuture {} impl> Future for GenFuture { type Output = T::Return; fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll { - 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), }) diff --git a/src/test/debuginfo/generators.rs b/src/test/debuginfo/generators.rs new file mode 100644 index 0000000000000..b56d222e0e01e --- /dev/null +++ b/src/test/debuginfo/generators.rs @@ -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() {()} diff --git a/src/test/run-pass/drop/dynamic-drop.rs b/src/test/run-pass/drop/dynamic-drop.rs index 41814f2af16b4..97e4cded80b9a 100644 --- a/src/test/run-pass/drop/dynamic-drop.rs +++ b/src/test/run-pass/drop/dynamic-drop.rs @@ -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(); } } diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs index 8e08de28bc6b2..613c495832f00 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -1,5 +1,6 @@ #![feature(generators, generator_trait)] +use std::marker::Unpin; use std::ops::Generator; pub fn foo() -> impl Generator { @@ -10,7 +11,7 @@ pub fn foo() -> impl Generator { } } -pub fn bar(t: T) -> Box> { +pub fn bar(t: T) -> Box + Unpin> { Box::new(|| { yield t; }) diff --git a/src/test/run-pass/generator/conditional-drop.rs b/src/test/run-pass/generator/conditional-drop.rs index 766eef9e3f3c3..907f7a3c06de7 100644 --- a/src/test/run-pass/generator/conditional-drop.rs +++ b/src/test/run-pass/generator/conditional-drop.rs @@ -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); } diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs index 2f499834796cc..df70e013bd330 100644 --- a/src/test/run-pass/generator/control-flow.rs +++ b/src/test/run-pass/generator/control-flow.rs @@ -2,13 +2,15 @@ #![feature(generators, generator_trait)] +use std::marker::Unpin; use std::ops::{GeneratorState, Generator}; +use std::pin::Pin; fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator + where T: Generator + 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); diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index 252f2c0f07da7..ac4e06656285e 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -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); diff --git a/src/test/run-pass/generator/issue-44197.rs b/src/test/run-pass/generator/issue-44197.rs index 4a6e5b88b235a..6efaff50c1e62 100644 --- a/src/test/run-pass/generator/issue-44197.rs +++ b/src/test/run-pass/generator/issue-44197.rs @@ -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 { } 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(())); } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 1011d54bdb33c..ac7e122dd5802 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -2,24 +2,26 @@ #![feature(generators, generator_trait)] +use std::marker::Unpin; use std::ops::{GeneratorState, Generator}; +use std::pin::Pin; struct W(T); // This impl isn't safe in general, but the generator used in this test is movable // so it won't cause problems. -impl> Iterator for W { +impl + Unpin> Iterator for W { type Item = T::Yield; fn next(&mut self) -> Option { - match unsafe { self.0.resume() } { + match Pin::new(&mut self.0).resume() { GeneratorState::Complete(..) => None, GeneratorState::Yielded(v) => Some(v), } } } -fn test() -> impl Generator { +fn test() -> impl Generator + Unpin { || { for i in 1..6 { yield i diff --git a/src/test/run-pass/generator/live-upvar-across-yield.rs b/src/test/run-pass/generator/live-upvar-across-yield.rs index b643809e50382..a1064165b2f7a 100644 --- a/src/test/run-pass/generator/live-upvar-across-yield.rs +++ b/src/test/run-pass/generator/live-upvar-across-yield.rs @@ -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(); } diff --git a/src/test/run-pass/generator/nested_generators.rs b/src/test/run-pass/generator/nested_generators.rs index e837e5fc9c1fe..b56cce1dc44f1 100644 --- a/src/test/run-pass/generator/nested_generators.rs +++ b/src/test/run-pass/generator/nested_generators.rs @@ -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; } diff --git a/src/test/run-pass/generator/non-static-is-unpin.rs b/src/test/run-pass/generator/non-static-is-unpin.rs new file mode 100644 index 0000000000000..96d0a8e283372 --- /dev/null +++ b/src/test/run-pass/generator/non-static-is-unpin.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(generators, generator_trait)] + +use std::marker::{PhantomPinned, Unpin}; + +fn assert_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); + }); +} diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 8640a6539195b..5ac97585f4b57 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -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); diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs index 134debdd23bc5..5f6778674dce1 100644 --- a/src/test/run-pass/generator/panic-safe.rs +++ b/src/test/run-pass/generator/panic-safe.rs @@ -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()); } diff --git a/src/test/run-pass/generator/pin-box-generator.rs b/src/test/run-pass/generator/pin-box-generator.rs new file mode 100644 index 0000000000000..c3136f5c0ec82 --- /dev/null +++ b/src/test/run-pass/generator/pin-box-generator.rs @@ -0,0 +1,13 @@ +// run-pass + +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn assert_generator(_: G) { +} + +fn main() { + assert_generator(static || yield); + assert_generator(Box::pin(static || yield)); +} diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index 2213c2f3fbae3..71a68ff684af3 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -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(_) => {} } diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index 8582941d610ca..533f2399084fa 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -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), } diff --git a/src/test/run-pass/generator/static-generators.rs b/src/test/run-pass/generator/static-generators.rs index eeaba3fe3c4c3..965d3c61c22d5 100644 --- a/src/test/run-pass/generator/static-generators.rs +++ b/src/test/run-pass/generator/static-generators.rs @@ -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(())); } diff --git a/src/test/run-pass/generator/xcrate-reachable.rs b/src/test/run-pass/generator/xcrate-reachable.rs index 403c920786e9c..9483ad7395ea1 100644 --- a/src/test/run-pass/generator/xcrate-reachable.rs +++ b/src/test/run-pass/generator/xcrate-reachable.rs @@ -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(); } diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs index 571b8fa9170f4..febf5c3583f30 100644 --- a/src/test/run-pass/generator/xcrate.rs +++ b/src/test/run-pass/generator/xcrate.rs @@ -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), } diff --git a/src/test/ui/generator/borrowing.nll.stderr b/src/test/ui/generator/borrowing.nll.stderr index af6ec4941d890..3c9221d28e74d 100644 --- a/src/test/ui/generator/borrowing.nll.stderr +++ b/src/test/ui/generator/borrowing.nll.stderr @@ -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 diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index 88a0cf9a77a54..9f8fc7483f64d 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -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 }; diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr index 3f5d32e1c3358..169e4a8561c1d 100644 --- a/src/test/ui/generator/borrowing.stderr +++ b/src/test/ui/generator/borrowing.stderr @@ -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 diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index 1f6b7db2bd853..a90a47fe9aa01 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -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 diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs index 1b0c1ebe517b4..65c61fbaac4e2 100644 --- a/src/test/ui/generator/dropck.rs +++ b/src/test/ui/generator/dropck.rs @@ -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 } diff --git a/src/test/ui/generator/dropck.stderr b/src/test/ui/generator/dropck.stderr index 281c9647bc3e1..fdaa5cfbae3e6 100644 --- a/src/test/ui/generator/dropck.stderr +++ b/src/test/ui/generator/dropck.stderr @@ -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 diff --git a/src/test/ui/generator/generator-region-requirements.ast.stderr b/src/test/ui/generator/generator-region-requirements.ast.stderr index 6a423aea7eceb..8a96d187f6b1c 100644 --- a/src/test/ui/generator/generator-region-requirements.ast.stderr +++ b/src/test/ui/generator/generator-region-requirements.ast.stderr @@ -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` diff --git a/src/test/ui/generator/generator-region-requirements.nll.stderr b/src/test/ui/generator/generator-region-requirements.nll.stderr index 6a423aea7eceb..8a96d187f6b1c 100644 --- a/src/test/ui/generator/generator-region-requirements.nll.stderr +++ b/src/test/ui/generator/generator-region-requirements.nll.stderr @@ -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` diff --git a/src/test/ui/generator/generator-region-requirements.rs b/src/test/ui/generator/generator-region-requirements.rs index 2cda483b6a1c2..9738f6c3932ed 100644 --- a/src/test/ui/generator/generator-region-requirements.rs +++ b/src/test/ui/generator/generator-region-requirements.rs @@ -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 diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr index 72a4654dec8b2..01eea627351fb 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr @@ -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 diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs index 332e074e9fe64..8c576581ad8dd 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs @@ -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 diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr index e1d718e847f8f..29299b2405a00 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr @@ -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 diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index e34731a4406d9..f64849b3149b8 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -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 } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 4f59f2c1c6ab3..c98f42e62168e 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -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 diff --git a/src/test/ui/generator/static-not-unpin.rs b/src/test/ui/generator/static-not-unpin.rs new file mode 100644 index 0000000000000..b271e982fb420 --- /dev/null +++ b/src/test/ui/generator/static-not-unpin.rs @@ -0,0 +1,15 @@ +#![feature(generators)] + +// normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin" + +use std::marker::Unpin; + +fn assert_unpin(_: T) { +} + +fn main() { + let mut generator = static || { + yield; + }; + assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied +} diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr new file mode 100644 index 0000000000000..caf92f0ec693e --- /dev/null +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -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) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr index bcbd68ab85d5c..2dc12f843b220 100644 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -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 diff --git a/src/test/ui/generator/yield-while-iterating.rs b/src/test/ui/generator/yield-while-iterating.rs index b0966d2e921b7..e42781d1279e7 100644 --- a/src/test/ui/generator/yield-while-iterating.rs +++ b/src/test/ui/generator/yield-while-iterating.rs @@ -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) { // 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() { } diff --git a/src/test/ui/generator/yield-while-iterating.stderr b/src/test/ui/generator/yield-while-iterating.stderr index aa66047feb227..1e3e31470e9d6 100644 --- a/src/test/ui/generator/yield-while-iterating.stderr +++ b/src/test/ui/generator/yield-while-iterating.stderr @@ -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 diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs index a895f05b34cae..38061e71358c4 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.rs +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -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() { } diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 765267a58b4a7..56f425b7e70a0 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -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; | ^^ diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr index 9a99b6ad02518..d0d6a98301e59 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr @@ -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 diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs index 540907a421dfb..f54a4f468f6a0 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.rs +++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs @@ -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() { } diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr index d70ef189ebc9a..5c9de279c02d8 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.stderr +++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr @@ -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 diff --git a/src/test/ui/nll/issue-55850.rs b/src/test/ui/nll/issue-55850.rs index eafbfd21700c8..8b5887224d19a 100644 --- a/src/test/ui/nll/issue-55850.rs +++ b/src/test/ui/nll/issue-55850.rs @@ -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); impl Iterator for GenIter where - G: Generator, + G: Generator + Unpin, { type Item = G::Yield; fn next(&mut self) -> Option { - unsafe { - match self.0.resume() { - Yielded(y) => Some(y), - _ => None - } + match Pin::new(&mut self.0).resume() { + Yielded(y) => Some(y), + _ => None } } }