From fca614eb578092fd869df57d6654ba0dcf92c6ef Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 24 Jan 2020 21:56:08 +0100 Subject: [PATCH] Add tests for generator resume arguments --- src/test/ui/generator/retain-resume-ref.rs | 25 +++++ .../ui/generator/retain-resume-ref.stderr | 13 +++ src/test/ui/generator/smoke-resume-args.rs | 97 +++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/test/ui/generator/retain-resume-ref.rs create mode 100644 src/test/ui/generator/retain-resume-ref.stderr create mode 100644 src/test/ui/generator/smoke-resume-args.rs diff --git a/src/test/ui/generator/retain-resume-ref.rs b/src/test/ui/generator/retain-resume-ref.rs new file mode 100644 index 000000000000..0606ea71cdf3 --- /dev/null +++ b/src/test/ui/generator/retain-resume-ref.rs @@ -0,0 +1,25 @@ +//! This test ensures that a mutable reference cannot be passed as a resume argument twice. + +#![feature(generators, generator_trait)] + +use std::marker::Unpin; +use std::ops::{ + Generator, + GeneratorState::{self, *}, +}; +use std::pin::Pin; + +fn main() { + let mut thing = String::from("hello"); + + let mut gen = |r| { + if false { + yield r; + } + }; + + let mut gen = Pin::new(&mut gen); + gen.as_mut().resume(&mut thing); + gen.as_mut().resume(&mut thing); + //~^ cannot borrow `thing` as mutable more than once at a time +} diff --git a/src/test/ui/generator/retain-resume-ref.stderr b/src/test/ui/generator/retain-resume-ref.stderr new file mode 100644 index 000000000000..e33310d12d9e --- /dev/null +++ b/src/test/ui/generator/retain-resume-ref.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `thing` as mutable more than once at a time + --> $DIR/retain-resume-ref.rs:23:25 + | +LL | gen.as_mut().resume(&mut thing); + | ---------- first mutable borrow occurs here +LL | gen.as_mut().resume(&mut thing); + | ------ ^^^^^^^^^^ second mutable borrow occurs here + | | + | first borrow later used by call + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/generator/smoke-resume-args.rs b/src/test/ui/generator/smoke-resume-args.rs new file mode 100644 index 000000000000..32f3ee32d77b --- /dev/null +++ b/src/test/ui/generator/smoke-resume-args.rs @@ -0,0 +1,97 @@ +// run-pass + +#![feature(generators, generator_trait)] + +use std::fmt::Debug; +use std::marker::Unpin; +use std::ops::{ + Generator, + GeneratorState::{self, *}, +}; +use std::pin::Pin; +use std::sync::atomic::{AtomicUsize, Ordering}; + +fn drain + Unpin, R, Y>( + gen: &mut G, + inout: Vec<(R, GeneratorState)>, +) where + Y: Debug + PartialEq, + G::Return: Debug + PartialEq, +{ + let mut gen = Pin::new(gen); + + for (input, out) in inout { + assert_eq!(gen.as_mut().resume(input), out); + } +} + +static DROPS: AtomicUsize = AtomicUsize::new(0); + +#[derive(Debug, PartialEq)] +struct DropMe; + +impl Drop for DropMe { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } +} + +fn expect_drops(expected_drops: usize, f: impl FnOnce() -> T) -> T { + DROPS.store(0, Ordering::SeqCst); + + let res = f(); + + let actual_drops = DROPS.load(Ordering::SeqCst); + assert_eq!(actual_drops, expected_drops); + res +} + +fn main() { + drain( + &mut |mut b| { + while b != 0 { + b = yield (b + 1); + } + -1 + }, + vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], + ); + + expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + + expect_drops(6, || { + drain( + &mut |a| yield yield a, + vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], + ) + }); + + #[allow(unreachable_code)] + expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + + expect_drops(2, || { + drain( + &mut |a: DropMe| { + if false { yield () } else { a } + }, + vec![(DropMe, Complete(DropMe))], + ) + }); + + expect_drops(4, || { + drain( + #[allow(unused_assignments, unused_variables)] + &mut |mut a: DropMe| { + a = yield; + a = yield; + a = yield; + }, + vec![ + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Complete(())), + ], + ) + }); +}