summaryrefslogtreecommitdiffstats
path: root/tests/ui/async-await/drop-order
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/async-await/drop-order
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/async-await/drop-order')
-rw-r--r--tests/ui/async-await/drop-order/auxiliary/arc_wake.rs64
-rw-r--r--tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs270
-rw-r--r--tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs265
-rw-r--r--tests/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs176
-rw-r--r--tests/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs98
-rw-r--r--tests/ui/async-await/drop-order/drop-order-locals-are-hidden.rs13
-rw-r--r--tests/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr27
-rw-r--r--tests/ui/async-await/drop-order/drop-order-when-cancelled.rs309
8 files changed, 1222 insertions, 0 deletions
diff --git a/tests/ui/async-await/drop-order/auxiliary/arc_wake.rs b/tests/ui/async-await/drop-order/auxiliary/arc_wake.rs
new file mode 100644
index 000000000..c21886f26
--- /dev/null
+++ b/tests/ui/async-await/drop-order/auxiliary/arc_wake.rs
@@ -0,0 +1,64 @@
+// edition:2018
+
+use std::sync::Arc;
+use std::task::{
+ Waker, RawWaker, RawWakerVTable,
+};
+
+macro_rules! waker_vtable {
+ ($ty:ident) => {
+ &RawWakerVTable::new(
+ clone_arc_raw::<$ty>,
+ wake_arc_raw::<$ty>,
+ wake_by_ref_arc_raw::<$ty>,
+ drop_arc_raw::<$ty>,
+ )
+ };
+}
+
+pub trait ArcWake {
+ fn wake(self: Arc<Self>);
+
+ fn wake_by_ref(arc_self: &Arc<Self>) {
+ arc_self.clone().wake()
+ }
+
+ fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
+ {
+ let ptr = Arc::into_raw(wake) as *const ();
+
+ unsafe {
+ Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
+ }
+ }
+}
+
+unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
+ // Retain Arc by creating a copy
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ let arc_clone = arc.clone();
+ // Forget the Arcs again, so that the refcount isn't decrased
+ let _ = Arc::into_raw(arc);
+ let _ = Arc::into_raw(arc_clone);
+}
+
+unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
+ increase_refcount::<T>(data);
+ RawWaker::new(data, waker_vtable!(T))
+}
+
+unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
+ // Drop Arc
+ let _: Arc<T> = Arc::from_raw(data as *const T);
+}
+
+unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ ArcWake::wake(arc);
+}
+
+unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
+ let arc: Arc<T> = Arc::from_raw(data as *const T);
+ ArcWake::wake_by_ref(&arc);
+ let _ = Arc::into_raw(arc);
+}
diff --git a/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs b/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs
new file mode 100644
index 000000000..9817d377a
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters-by-ref-binding.rs
@@ -0,0 +1,270 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn completes execution.
+// See also #54716.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foo_sync(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn bar_sync(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn baz_sync((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+ /// Check that unused bindings are dropped after the method is polled.
+ async fn foo_async(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method is polled.
+ async fn bar_async(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// is polled.
+ async fn baz_async((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync((ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method is polled.
+ async fn foobar_async(
+ ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(
+ ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+ /// Check that unused bindings are dropped after the method with self is polled.
+ async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method with self is polled.
+ async fn bar_async(&'a self, ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(&'a self, ref mut x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// with self is polled.
+ async fn baz_async(&'a self, (ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync(&'a self, (ref mut x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method with self is polled.
+ async fn foobar_async(
+ &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(
+ &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D,
+ ) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods w/out self (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ Foo::foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ Foo::foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods (see doc comment on function for what it tests).
+ let b = Bar(Default::default());
+ assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ b.foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ b.foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+}
diff --git a/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs b/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs
new file mode 100644
index 000000000..6c10ead36
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-for-async-fn-parameters.rs
@@ -0,0 +1,265 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![allow(unused_variables)]
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn completes execution.
+// See also #54716.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+ /// Check that unused bindings are dropped after the method is polled.
+ async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method is polled.
+ async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// is polled.
+ async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method is polled.
+ async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+ /// Check that unused bindings are dropped after the method with self is polled.
+ async fn foo_async(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foo_sync(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method with self is polled.
+ async fn bar_async(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn bar_sync(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// with self is polled.
+ async fn baz_async(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn baz_sync(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method with self is polled.
+ async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods w/out self (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ Foo::foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ Foo::foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods (see doc comment on function for what it tests).
+ let b = Bar(Default::default());
+ assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
+ assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
+ assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
+ assert_drop_order_after_poll(
+ |l| {
+ b.foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ b.foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+}
diff --git a/tests/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs b/tests/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs
new file mode 100644
index 000000000..15cc9fbc8
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-for-locals-when-cancelled.rs
@@ -0,0 +1,176 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![deny(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+#![allow(path_statements)]
+
+// Test that the drop order for locals in a fn and async fn matches up.
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::sync::Arc;
+use std::task::{Context, Poll};
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+struct NeverReady;
+
+impl Future for NeverReady {
+ type Output = ();
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ Poll::Pending
+ }
+}
+
+async fn simple_variable_declaration_async(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ NeverReady.await;
+}
+
+fn simple_variable_declaration_sync(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+}
+
+async fn varable_completely_contained_within_block_async(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ async {
+ let x = D("x", l.clone());
+ }
+ .await;
+ let y = D("y", l.clone());
+ NeverReady.await;
+}
+
+fn varable_completely_contained_within_block_sync(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ {
+ let x = D("x", l.clone());
+ }
+ let y = D("y", l.clone());
+}
+
+async fn variables_moved_into_separate_blocks_async(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ async move { x }.await;
+ async move { y }.await;
+ NeverReady.await;
+}
+
+fn variables_moved_into_separate_blocks_sync(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ {
+ x
+ };
+ {
+ y
+ };
+}
+
+async fn variables_moved_into_same_block_async(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ async move {
+ x;
+ y;
+ };
+ NeverReady.await;
+}
+
+fn variables_moved_into_same_block_sync(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ {
+ x;
+ y;
+ };
+ return;
+}
+
+async fn move_after_current_await_doesnt_affect_order(l: DropOrderListPtr) {
+ l.borrow_mut().push(DropOrder::Function);
+ let x = D("x", l.clone());
+ let y = D("y", l.clone());
+ NeverReady.await;
+ async move {
+ x;
+ y;
+ };
+}
+
+fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+ drop(fut);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ assert_drop_order_after_cancel(
+ simple_variable_declaration_async,
+ simple_variable_declaration_sync,
+ );
+ assert_drop_order_after_cancel(
+ varable_completely_contained_within_block_async,
+ varable_completely_contained_within_block_sync,
+ );
+ assert_drop_order_after_cancel(
+ variables_moved_into_separate_blocks_async,
+ variables_moved_into_separate_blocks_sync,
+ );
+ assert_drop_order_after_cancel(
+ variables_moved_into_same_block_async,
+ variables_moved_into_same_block_sync,
+ );
+ assert_drop_order_after_cancel(
+ move_after_current_await_doesnt_affect_order,
+ simple_variable_declaration_sync,
+ );
+}
diff --git a/tests/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs b/tests/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs
new file mode 100644
index 000000000..edfecb910
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-for-temporary-in-tail-return-expr.rs
@@ -0,0 +1,98 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![allow(unused_variables)]
+
+// Test the drop order for parameters relative to local variables and
+// temporaries created in the tail return expression of the function
+// body. In particular, check that this drop order is the same between
+// an `async fn` and an ordinary `fn`. See #64512.
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::sync::Arc;
+use std::rc::Rc;
+use std::task::Context;
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+/// Check drop order of temporary "temp" as compared to `x`, `y`, and `z`.
+///
+/// Expected order:
+/// - `z`
+/// - temp
+/// - `y`
+/// - `x`
+async fn foo_async(x: D, _y: D) {
+ let l = x.1.clone();
+ let z = D("z", l.clone());
+ l.borrow_mut().push(DropOrder::Function);
+ helper_async(&D("temp", l)).await
+}
+
+async fn helper_async(v: &D) { }
+
+fn foo_sync(x: D, _y: D) {
+ let l = x.1.clone();
+ let z = D("z", l.clone());
+ l.borrow_mut().push(DropOrder::Function);
+ helper_sync(&D("temp", l))
+}
+
+fn helper_sync(v: &D) { }
+
+fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let r = fut.as_mut().poll(&mut cx);
+
+ assert!(match r {
+ std::task::Poll::Ready(()) => true,
+ _ => false,
+ });
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
+}
diff --git a/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.rs b/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.rs
new file mode 100644
index 000000000..79dedb1ba
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.rs
@@ -0,0 +1,13 @@
+// edition:2018
+
+async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
+ assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
+ assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
+}
+
+async fn baz_async(ref mut x: u32, ref y: u32) {
+ assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425]
+ assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425]
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr b/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr
new file mode 100644
index 000000000..aa04a613f
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-locals-are-hidden.stderr
@@ -0,0 +1,27 @@
+error[E0425]: cannot find value `__arg1` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:4:16
+ |
+LL | assert_eq!(__arg1, (1, 2, 3));
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg2` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:5:16
+ |
+LL | assert_eq!(__arg2, 4);
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg0` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:9:16
+ |
+LL | assert_eq!(__arg0, 1);
+ | ^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `__arg1` in this scope
+ --> $DIR/drop-order-locals-are-hidden.rs:10:16
+ |
+LL | assert_eq!(__arg1, 2);
+ | ^^^^^^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/async-await/drop-order/drop-order-when-cancelled.rs b/tests/ui/async-await/drop-order/drop-order-when-cancelled.rs
new file mode 100644
index 000000000..cfd68bc0d
--- /dev/null
+++ b/tests/ui/async-await/drop-order/drop-order-when-cancelled.rs
@@ -0,0 +1,309 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+// Test that the drop order for parameters in a fn and async fn matches up. Also test that
+// parameters (used or unused) are not dropped until the async fn is cancelled.
+// This file is mostly copy-pasted from drop-order-for-async-fn-parameters.rs
+
+#![allow(unused_variables)]
+
+extern crate arc_wake;
+
+use arc_wake::ArcWake;
+use std::cell::RefCell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::sync::Arc;
+use std::task::{Context, Poll};
+
+struct EmptyWaker;
+
+impl ArcWake for EmptyWaker {
+ fn wake(self: Arc<Self>) {}
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum DropOrder {
+ Function,
+ Val(&'static str),
+}
+
+type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
+
+struct D(&'static str, DropOrderListPtr);
+
+impl Drop for D {
+ fn drop(&mut self) {
+ self.1.borrow_mut().push(DropOrder::Val(self.0));
+ }
+}
+
+struct NeverReady;
+
+impl Future for NeverReady {
+ type Output = ();
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ Poll::Pending
+ }
+}
+
+/// Check that unused bindings are dropped after the function is polled.
+async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+}
+
+fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns are dropped after the function is polled.
+async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+}
+
+fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore patterns within more complex patterns are dropped after the function
+/// is polled.
+async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+}
+
+fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
+/// after the function is polled.
+async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+}
+
+fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+}
+
+struct Foo;
+
+impl Foo {
+ /// Check that unused bindings are dropped after the method is polled.
+ async fn foo_async(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn foo_sync(x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method is polled.
+ async fn bar_async(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn bar_sync(x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// is polled.
+ async fn baz_async((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn baz_sync((x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method is polled.
+ async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+struct Bar<'a>(PhantomData<&'a ()>);
+
+impl<'a> Bar<'a> {
+ /// Check that unused bindings are dropped after the method with self is polled.
+ async fn foo_async(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn foo_sync(&'a self, x: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns are dropped after the method with self is polled.
+ async fn bar_async(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn bar_sync(&'a self, x: D, _: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore patterns within more complex patterns are dropped after the method
+ /// with self is polled.
+ async fn baz_async(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn baz_sync(&'a self, (x, _): (D, D)) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+
+ /// Check that underscore and unused bindings within and outwith more complex patterns are
+ /// dropped after the method with self is polled.
+ async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ NeverReady.await;
+ }
+
+ fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
+ x.1.borrow_mut().push(DropOrder::Function);
+ }
+}
+
+fn assert_drop_order_after_cancel<Fut: Future<Output = ()>>(
+ f: impl FnOnce(DropOrderListPtr) -> Fut,
+ g: impl FnOnce(DropOrderListPtr),
+) {
+ let empty = Arc::new(EmptyWaker);
+ let waker = ArcWake::into_waker(empty);
+ let mut cx = Context::from_waker(&waker);
+
+ let actual_order = Rc::new(RefCell::new(Vec::new()));
+ let mut fut = Box::pin(f(actual_order.clone()));
+ let _ = fut.as_mut().poll(&mut cx);
+
+ // Parameters are never dropped until the future completes.
+ assert_eq!(*actual_order.borrow(), vec![DropOrder::Function]);
+
+ drop(fut);
+
+ let expected_order = Rc::new(RefCell::new(Vec::new()));
+ g(expected_order.clone());
+ assert_eq!(*actual_order.borrow(), *expected_order.borrow());
+}
+
+fn main() {
+ // Free functions (see doc comment on function for what it tests).
+ assert_drop_order_after_cancel(
+ |l| foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| foo_sync(D("x", l.clone()), D("_y", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| bar_sync(D("x", l.clone()), D("_", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| baz_sync((D("x", l.clone()), D("_", l.clone()))),
+ );
+ assert_drop_order_after_cancel(
+ |l| {
+ foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods w/out self (see doc comment on function for what it tests).
+ assert_drop_order_after_cancel(
+ |l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))),
+ );
+ assert_drop_order_after_cancel(
+ |l| {
+ Foo::foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ Foo::foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+
+ // Methods (see doc comment on function for what it tests).
+ let b = Bar(Default::default());
+ assert_drop_order_after_cancel(
+ |l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
+ |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
+ |l| b.bar_sync(D("x", l.clone()), D("_", l.clone())),
+ );
+ assert_drop_order_after_cancel(
+ |l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
+ |l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))),
+ );
+ assert_drop_order_after_cancel(
+ |l| {
+ b.foobar_async(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ |l| {
+ b.foobar_sync(
+ D("x", l.clone()),
+ (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
+ D("_", l.clone()),
+ D("_y", l.clone()),
+ )
+ },
+ );
+}