From 3b4cbe9095d83d13feb13060cc66f3e50bd75350 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 3 Dec 2022 18:38:04 +0100
Subject: [PATCH] add test for self-referential future

---
 .../future-self-referential.rs                | 102 ++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs

diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
new file mode 100644
index 00000000000..3ba21552fd3
--- /dev/null
+++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
@@ -0,0 +1,102 @@
+#![feature(pin_macro)]
+
+use std::future::*;
+use std::marker::PhantomPinned;
+use std::pin::*;
+use std::ptr;
+use std::task::*;
+
+struct Delay {
+    delay: usize,
+}
+
+impl Delay {
+    fn new(delay: usize) -> Self {
+        Delay { delay }
+    }
+}
+
+impl Future for Delay {
+    type Output = ();
+    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
+        if self.delay > 0 {
+            self.delay -= 1;
+            Poll::Pending
+        } else {
+            Poll::Ready(())
+        }
+    }
+}
+
+async fn do_stuff() {
+    (&mut Delay::new(1)).await;
+}
+
+// Same thing implemented by hand
+struct DoStuff {
+    state: usize,
+    delay: Delay,
+    delay_ref: *mut Delay,
+    _marker: PhantomPinned,
+}
+
+impl DoStuff {
+    fn new() -> Self {
+        DoStuff {
+            state: 0,
+            delay: Delay::new(1),
+            delay_ref: ptr::null_mut(),
+            _marker: PhantomPinned,
+        }
+    }
+}
+
+impl Future for DoStuff {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+        unsafe {
+            let this = self.get_unchecked_mut();
+            match this.state {
+                0 => {
+                    // Set up self-ref.
+                    this.delay_ref = &mut this.delay;
+                    // Move to next state.
+                    this.state = 1;
+                    Poll::Pending
+                }
+                1 => {
+                    let delay = &mut *this.delay_ref;
+                    Pin::new_unchecked(delay).poll(cx)
+                }
+                _ => unreachable!(),
+            }
+        }
+    }
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+    use std::sync::Arc;
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    let waker = Waker::from(Arc::new(MyWaker));
+    let mut context = Context::from_waker(&waker);
+
+    let mut pinned = pin!(fut);
+    loop {
+        match pinned.as_mut().poll(&mut context) {
+            Poll::Pending => continue,
+            Poll::Ready(v) => return v,
+        }
+    }
+}
+
+fn main() {
+    run_fut(do_stuff());
+    run_fut(DoStuff::new());
+}