about summary refs log tree commit diff
path: root/src/tools/miri/tests/fail/coroutine-pinned-moved.rs
blob: abed638e44359768af9561eaafc072e81fbb3ac2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]

use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;

fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
    #[coroutine]
    static move || {
        let mut num = 0;
        let num = &mut num;
        *num += 0;

        yield *num;
        *num += 1; //~ERROR: has been freed
    }
}

struct CoroutineIteratorAdapter<G>(G);

impl<G> Iterator for CoroutineIteratorAdapter<G>
where
    G: Coroutine<Return = ()>,
{
    type Item = G::Yield;

    fn next(&mut self) -> Option<Self::Item> {
        let me = unsafe { Pin::new_unchecked(&mut self.0) };
        match me.resume(()) {
            CoroutineState::Yielded(x) => Some(x),
            CoroutineState::Complete(_) => None,
        }
    }
}

fn main() {
    let mut coroutine_iterator_2 = {
        let mut coroutine_iterator = Box::new(CoroutineIteratorAdapter(firstn()));
        coroutine_iterator.next(); // pin it

        Box::new(*coroutine_iterator) // move it
    }; // *deallocate* coroutine_iterator

    coroutine_iterator_2.next(); // and use moved value
}