blob: c5ab3fcb8e28feb7e1ae942f00caf1a71be22999 [file] [edit]
//@edition: 2024
//@revisions: stack tree tree_implicit_writes
//@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(gen_blocks)]
fn main() {
basic();
iterate();
movable_gen();
movable_gen2();
}
fn basic() {
gen fn foo() -> i32 {
yield 42;
for i in 5..10 {
if i % 2 == 0 {
continue;
}
yield i * 2;
}
}
let v = foo().collect::<Vec<_>>();
assert_eq!(v, &[42, 10, 14, 18]);
}
fn iterate() {
fn foo() -> impl Iterator<Item = u32> {
gen {
yield 42;
for x in 3..6 {
yield x
}
}
}
fn moved() -> impl Iterator<Item = u32> {
let mut x = "foo".to_string();
gen move {
yield 42;
if x == "foo" {
return;
}
x.clear();
for x in 3..6 {
yield x
}
}
}
let mut iter = foo();
assert_eq!(iter.next(), Some(42));
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next(), None);
// `gen` blocks are fused
assert_eq!(iter.next(), None);
let mut iter = moved();
assert_eq!(iter.next(), Some(42));
assert_eq!(iter.next(), None);
}
/// Ensure a generator can reborrow from a reference it captured.
/// Regression test for <https://github.com/rust-lang/rust/issues/159443>.
pub fn movable_gen() {
fn make_gen(r: &mut u8) -> impl Iterator<Item = u8> {
gen move {
let a = r;
*a = 1;
yield 1;
*a = 2;
}
}
let mut a = 1;
let mut i = make_gen(&mut a);
assert_eq!(i.next(), Some(1));
let mut j = i;
assert_eq!(j.next(), None);
}
/// Regression test for <https://github.com/rust-lang/rust/issues/161026>.
fn movable_gen2() {
// a struct that has a drop flag and contains a reference
struct DropMut<T: 'static>(&'static mut T);
impl<T: 'static> Drop for DropMut<T> {
fn drop(&mut self) {
drop(unsafe { Box::from_raw(self.0) });
}
}
let mut a = gen {
let b = DropMut(Box::leak(Box::new(1)));
// create a drop flag on `b`
let c;
if true {
c = b; // and ensure it's set to false
} else {
c = DropMut(Box::leak(Box::new(2)));
}
*c.0 = 3;
4.yield;
*c.0 = 5;
};
let _ = a.next();
let mut d = a;
let _ = d.next();
}