about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/lowering.rs39
-rw-r--r--src/librustc/hir/map/def_collector.rs13
-rw-r--r--src/librustc/lint/context.rs15
-rw-r--r--src/librustc_resolve/lib.rs15
-rw-r--r--src/libsyntax/ast.rs12
-rw-r--r--src/libsyntax/ext/placeholders.rs5
-rw-r--r--src/libsyntax/mut_visit.rs14
-rw-r--r--src/libsyntax/parse/parser.rs62
-rw-r--r--src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs263
-rw-r--r--src/test/run-pass/issue-54716.rs184
10 files changed, 401 insertions, 221 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index df455a725c5..e7fe9bf40ba 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> {
             if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
                 let mut body = body.clone();
 
+                // Async function arguments are lowered into the closure body so that they are
+                // captured and so that the drop order matches the equivalent non-async functions.
+                //
+                //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+                //       async move {
+                //       }
+                //     }
+                //
+                //     // ...becomes...
+                //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+                //       async move {
+                //         let __arg2 = __arg2;
+                //         let <pattern> = __arg2;
+                //         let __arg1 = __arg1;
+                //         let <pattern> = __arg1;
+                //         let __arg0 = __arg0;
+                //         let <pattern> = __arg0;
+                //       }
+                //     }
+                //
+                // If `<pattern>` is a simple ident, then it is lowered to a single
+                // `let <pattern> = <pattern>;` statement as an optimization.
                 for a in arguments.iter().rev() {
-                    body.stmts.insert(0, a.stmt.clone());
+                    if let Some(pat_stmt) = a.pat_stmt.clone() {
+                        body.stmts.insert(0, pat_stmt);
+                    }
+                    body.stmts.insert(0, a.move_stmt.clone());
                 }
 
                 let async_expr = this.make_async_expr(
@@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> {
                         let mut decl = decl.clone();
                         // Replace the arguments of this async function with the generated
                         // arguments that will be moved into the closure.
-                        decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
+                        for (i, a) in arguments.clone().drain(..).enumerate() {
+                            if let Some(arg) = a.arg {
+                                decl.inputs[i] = arg;
+                            }
+                        }
                         lower_fn(&decl)
                     } else {
                         lower_fn(decl)
@@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> {
                     let mut sig = sig.clone();
                     // Replace the arguments of this async function with the generated
                     // arguments that will be moved into the closure.
-                    sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
+                    for (i, a) in arguments.clone().drain(..).enumerate() {
+                        if let Some(arg) = a.arg {
+                            sig.decl.inputs[i] = arg;
+                        }
+                    }
                     lower_method(&sig)
                 } else {
                     lower_method(sig)
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 0fa97385322..78de8539859 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> {
             // Walk the generated arguments for the `async fn`.
             for a in arguments {
                 use visit::Visitor;
-                this.visit_ty(&a.arg.ty);
+                if let Some(arg) = &a.arg {
+                    this.visit_ty(&arg.ty);
+                }
             }
 
             // We do not invoke `walk_fn_decl` as this will walk the arguments that are being
@@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> {
                 *closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
             );
             this.with_parent(closure_def, |this| {
+                use visit::Visitor;
+                // Walk each of the generated statements before the regular block body.
                 for a in arguments {
-                    use visit::Visitor;
-                    // Walk each of the generated statements before the regular block body.
-                    this.visit_stmt(&a.stmt);
+                    this.visit_stmt(&a.move_stmt);
+                    if let Some(pat_stmt) = &a.pat_stmt {
+                        this.visit_stmt(&pat_stmt);
+                    }
                 }
 
                 visit::walk_block(this, &body);
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index f5cb4cfa29f..8d5c1798e0f 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
             for a in arguments {
                 // Visit the argument..
-                self.visit_pat(&a.arg.pat);
-                if let ast::ArgSource::AsyncFn(pat) = &a.arg.source {
-                    self.visit_pat(pat);
+                if let Some(arg) = &a.arg {
+                    self.visit_pat(&arg.pat);
+                    if let ast::ArgSource::AsyncFn(pat) = &arg.source {
+                        self.visit_pat(pat);
+                    }
+                    self.visit_ty(&arg.ty);
                 }
-                self.visit_ty(&a.arg.ty);
 
                 // ..and the statement.
-                self.visit_stmt(&a.stmt);
+                self.visit_stmt(&a.move_stmt);
+                if let Some(pat_stmt) = &a.pat_stmt {
+                    self.visit_stmt(&pat_stmt);
+                }
             }
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index be68f303537..281be201a66 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         // Walk the generated async arguments if this is an `async fn`, otherwise walk the
         // normal arguments.
         if let IsAsync::Async { ref arguments, .. } = asyncness {
-            for a in arguments { add_argument(&a.arg); }
+            for (i, a) in arguments.iter().enumerate() {
+                if let Some(arg) = &a.arg {
+                    add_argument(&arg);
+                } else {
+                    add_argument(&declaration.inputs[i]);
+                }
+            }
         } else {
             for a in &declaration.inputs { add_argument(a); }
         }
@@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                     let mut body = body.clone();
                     // Insert the generated statements into the body before attempting to
                     // resolve names.
-                    for a in arguments {
-                        body.stmts.insert(0, a.stmt.clone());
+                    for a in arguments.iter().rev() {
+                        if let Some(pat_stmt) = a.pat_stmt.clone() {
+                            body.stmts.insert(0, pat_stmt);
+                        }
+                        body.stmts.insert(0, a.move_stmt.clone());
                     }
                     self.visit_block(&body);
                 } else {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a20bf91a6ad..33b8c76bb53 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1865,10 +1865,14 @@ pub enum Unsafety {
 pub struct AsyncArgument {
     /// `__arg0`
     pub ident: Ident,
-    /// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
-    pub arg: Arg,
-    /// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
-    pub stmt: Stmt,
+    /// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`. Only if
+    /// argument is not a simple binding.
+    pub arg: Option<Arg>,
+    /// `let __arg0 = __arg0;` statement to be inserted at the start of the block.
+    pub move_stmt: Stmt,
+    /// `let <pat> = __arg0;` statement to be inserted at the start of the block, after matching
+    /// move statement. Only if argument is not a simple binding.
+    pub pat_stmt: Option<Stmt>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 68cd3c28676..f5e18e98436 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
 
         if let ast::IsAsync::Async { ref mut arguments, .. } = a {
             for argument in arguments.iter_mut() {
-                self.next_id(&mut argument.stmt.id);
+                self.next_id(&mut argument.move_stmt.id);
+                if let Some(ref mut pat_stmt) = &mut argument.pat_stmt {
+                    self.next_id(&mut pat_stmt.id);
+                }
             }
         }
     }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index d3441a2039b..2e09235ca77 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -694,13 +694,21 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
         IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
             vis.visit_id(closure_id);
             vis.visit_id(return_impl_trait_id);
-            for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
+            for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() {
                 vis.visit_ident(ident);
-                vis.visit_arg(arg);
-                visit_clobber(stmt, |stmt| {
+                if let Some(arg) = arg {
+                    vis.visit_arg(arg);
+                }
+                visit_clobber(move_stmt, |stmt| {
                     vis.flat_map_stmt(stmt)
                         .expect_one("expected visitor to produce exactly one item")
                 });
+                visit_opt(pat_stmt, |stmt| {
+                    visit_clobber(stmt, |stmt| {
+                        vis.flat_map_stmt(stmt)
+                            .expect_one("expected visitor to produce exactly one item")
+                    })
+                });
             }
         }
         IsAsync::NotAsync => {}
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8efe84cdf01..a10ee17b7e7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -8880,11 +8880,37 @@ impl<'a> Parser<'a> {
                 let name = format!("__arg{}", index);
                 let ident = Ident::from_str(&name);
 
+                // Check if this is a ident pattern, if so, we can optimize and avoid adding a
+                // `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
+                // statement.
+                let (ident, is_simple_pattern) = match input.pat.node {
+                    PatKind::Ident(_, ident, _) => (ident, true),
+                    _ => (ident, false),
+                };
+
                 // Construct an argument representing `__argN: <ty>` to replace the argument of the
-                // async function.
-                let arg = Arg {
-                    ty: input.ty.clone(),
-                    id,
+                // async function if it isn't a simple pattern.
+                let arg = if is_simple_pattern {
+                    None
+                } else {
+                    Some(Arg {
+                        ty: input.ty.clone(),
+                        id,
+                        pat: P(Pat {
+                            id,
+                            node: PatKind::Ident(
+                                BindingMode::ByValue(Mutability::Immutable), ident, None,
+                            ),
+                            span,
+                        }),
+                        source: ArgSource::AsyncFn(input.pat.clone()),
+                    })
+                };
+
+                // Construct a `let __argN = __argN;` statement to insert at the top of the
+                // async closure. This makes sure that the argument is captured by the closure and
+                // that the drop order is correct.
+                let move_local = Local {
                     pat: P(Pat {
                         id,
                         node: PatKind::Ident(
@@ -8892,13 +8918,6 @@ impl<'a> Parser<'a> {
                         ),
                         span,
                     }),
-                    source: ArgSource::AsyncFn(input.pat.clone()),
-                };
-
-                // Construct a `let <pat> = __argN;` statement to insert at the top of the
-                // async closure.
-                let local = P(Local {
-                    pat: input.pat.clone(),
                     // We explicitly do not specify the type for this statement. When the user's
                     // argument type is `impl Trait` then this would require the
                     // `impl_trait_in_bindings` feature to also be present for that same type to
@@ -8918,10 +8937,25 @@ impl<'a> Parser<'a> {
                     span,
                     attrs: ThinVec::new(),
                     source: LocalSource::AsyncFn,
-                });
-                let stmt = Stmt { id, node: StmtKind::Local(local), span, };
+                };
+
+                // Construct a `let <pat> = __argN;` statement to insert at the top of the
+                // async closure if this isn't a simple pattern.
+                let pat_stmt = if is_simple_pattern {
+                    None
+                } else {
+                    Some(Stmt {
+                        id,
+                        node: StmtKind::Local(P(Local {
+                            pat: input.pat.clone(),
+                            ..move_local.clone()
+                        })),
+                        span,
+                    })
+                };
 
-                arguments.push(AsyncArgument { ident, arg, stmt });
+                let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
+                arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
             }
         }
     }
diff --git a/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs
new file mode 100644
index 00000000000..708c5704984
--- /dev/null
+++ b/src/test/run-pass/async-await-drop-order-for-async-fn-parameters.rs
@@ -0,0 +1,263 @@
+// aux-build:arc_wake.rs
+// edition:2018
+// run-pass
+
+#![allow(unused_variables)]
+#![feature(async_await, await_macro)]
+
+// 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/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs
deleted file mode 100644
index 961c412f5ec..00000000000
--- a/src/test/run-pass/issue-54716.rs
+++ /dev/null
@@ -1,184 +0,0 @@
-// aux-build:arc_wake.rs
-// edition:2018
-// run-pass
-
-#![allow(unused_variables)]
-#![feature(async_await, await_macro)]
-
-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(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(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((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(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(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(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((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(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(&'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(&'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(&'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(&'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,
-    expected_order: &[DropOrder],
-) {
-    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);
-
-    assert_eq!(*actual_order.borrow(), expected_order);
-}
-
-fn main() {
-    use DropOrder::*;
-
-    // At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as
-    // the equivalent non-async functions. This is because the drop order of captured variables
-    // doesn't match the drop order of arguments in a function.
-
-    // Free functions (see doc comment on function for what it tests).
-    assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-
-    // Methods w/out self (see doc comment on function for what it tests).
-    assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        Foo::foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-
-    // Methods (see doc comment on function for what it tests).
-    let b = Bar(Default::default());
-    assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())),
-                                 &[Function, Val("_y"), Val("x")]);
-    assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))),
-                                 &[Function, Val("x"), Val("_")]);
-    assert_drop_order_after_poll(|l| {
-        b.foobar(
-            D("x", l.clone()),
-            (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
-            D("_", l.clone()),
-            D("_y", l.clone()),
-        )
-    }, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
-}