about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs10
-rw-r--r--src/librustc/hir/lowering.rs294
-rw-r--r--src/librustc/hir/map/mod.rs13
-rw-r--r--src/librustc/hir/mod.rs14
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs6
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs3
-rw-r--r--src/librustc/middle/resolve_lifetime.rs3
-rw-r--r--src/librustc_mir/build/mod.rs66
-rw-r--r--src/librustc_privacy/lib.rs20
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/librustc_typeck/check/writeback.rs10
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/test/ui/async-await/issues/issue-61187.rs9
-rw-r--r--src/test/ui/async-await/issues/issue-61187.stderr11
14 files changed, 317 insertions, 155 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 8000666044a..9cf365addca 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -262,9 +262,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_pat(&mut self, p: &'v Pat) {
         walk_pat(self, p)
     }
-    fn visit_argument_source(&mut self, s: &'v ArgSource) {
-        walk_argument_source(self, s)
-    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -402,17 +399,10 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
     for argument in &body.arguments {
         visitor.visit_id(argument.hir_id);
         visitor.visit_pat(&argument.pat);
-        visitor.visit_argument_source(&argument.source);
     }
     visitor.visit_expr(&body.value);
 }
 
-pub fn walk_argument_source<'v, V: Visitor<'v>>(visitor: &mut V, source: &'v ArgSource) {
-    if let ArgSource::AsyncFn(pat) = source {
-        visitor.visit_pat(pat);
-    }
-}
-
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     // Intentionally visiting the expr first - the initialization expr
     // dominates the local's definition.
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index df0a23c1b86..e82b3df8550 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -781,7 +781,7 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
+    fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
         if self.is_generator && self.is_async_body {
             span_err!(
                 self.sess,
@@ -1121,27 +1121,21 @@ impl<'a> LoweringContext<'a> {
         span: Span,
         body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
     ) -> hir::ExprKind {
-        let prev_is_generator = mem::replace(&mut self.is_generator, false);
-        let prev_is_async_body = mem::replace(&mut self.is_async_body, true);
+        let capture_clause = self.lower_capture_clause(capture_clause);
         let output = match ret_ty {
             Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
             None => FunctionRetTy::Default(span),
         };
-        let decl = FnDecl {
+        let ast_decl = FnDecl {
             inputs: vec![],
             output,
             c_variadic: false
         };
-        // Lower the arguments before the body otherwise the body will call `lower_res` expecting
-        // the argument to have been assigned an id already.
-        let arguments = self.lower_args(Some(&decl));
-        let body_expr = body(self);
-        let body_id = self.record_body(body_expr, arguments);
-        self.is_generator = prev_is_generator;
-        self.is_async_body = prev_is_async_body;
-
-        let capture_clause = self.lower_capture_clause(capture_clause);
-        let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
+        let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
+        let body_id = self.lower_fn_body(&ast_decl, |this| {
+            this.is_async_body = true;
+            body(this)
+        });
         let generator = hir::Expr {
             hir_id: self.lower_node_id(closure_node_id),
             node: hir::ExprKind::Closure(capture_clause, decl, body_id, span,
@@ -1160,18 +1154,32 @@ impl<'a> LoweringContext<'a> {
         hir::ExprKind::Call(P(gen_future), hir_vec![generator])
     }
 
-    fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
-    where
-        F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
-    {
-        let prev_generator = mem::replace(&mut self.is_generator, false);
-        let prev_async = mem::replace(&mut self.is_async_body, false);
-        let arguments = self.lower_args(decl);
-        let result = f(self);
-        let r = self.record_body(result, arguments);
-        self.is_generator = prev_generator;
-        self.is_async_body = prev_async;
-        return r;
+    fn lower_body(
+        &mut self,
+        f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
+    ) -> hir::BodyId {
+        let prev_is_generator = mem::replace(&mut self.is_generator, false);
+        let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
+        let (arguments, result) = f(self);
+        let body_id = self.record_body(arguments, result);
+        self.is_generator = prev_is_generator;
+        self.is_async_body = prev_is_async_body;
+        body_id
+    }
+
+    fn lower_fn_body(
+        &mut self,
+        decl: &FnDecl,
+        body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
+    ) -> hir::BodyId {
+        self.lower_body(|this| (
+            decl.inputs.iter().map(|x| this.lower_arg(x)).collect(),
+            body(this),
+        ))
+    }
+
+    fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
+        self.lower_body(|this| (hir_vec![], this.lower_expr(expr)))
     }
 
     fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
@@ -2273,10 +2281,6 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_args(&mut self, decl: Option<&FnDecl>) -> HirVec<hir::Arg> {
-        decl.map_or(hir_vec![], |decl| decl.inputs.iter().map(|x| self.lower_arg(x)).collect())
-    }
-
     fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
         hir::Arg {
             hir_id: self.lower_node_id(arg.id),
@@ -2980,11 +2984,14 @@ impl<'a> LoweringContext<'a> {
         bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
     }
 
-    fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+    fn lower_block_with_stmts(
+        &mut self,
+        b: &Block,
+        targeted_by_break: bool,
+        mut stmts: Vec<hir::Stmt>,
+    ) -> P<hir::Block> {
         let mut expr = None;
 
-        let mut stmts = vec![];
-
         for (index, stmt) in b.stmts.iter().enumerate() {
             if index == b.stmts.len() - 1 {
                 if let StmtKind::Expr(ref e) = stmt.node {
@@ -3007,25 +3014,177 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_async_body(
+    fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+        self.lower_block_with_stmts(b, targeted_by_break, vec![])
+    }
+
+    fn lower_maybe_async_body(
         &mut self,
         decl: &FnDecl,
         asyncness: IsAsync,
         body: &Block,
     ) -> hir::BodyId {
-        self.lower_body(Some(&decl), |this| {
-            if let IsAsync::Async { closure_id, .. } = asyncness {
-                let async_expr = this.make_async_expr(
-                    CaptureBy::Value, closure_id, None, body.span,
-                    |this| {
-                        let body = this.lower_block(&body, false);
-                        this.expr_block(body, ThinVec::new())
-                    });
-                this.expr(body.span, async_expr, ThinVec::new())
-            } else {
+        let closure_id = match asyncness {
+            IsAsync::Async { closure_id, .. } => closure_id,
+            IsAsync::NotAsync => return self.lower_fn_body(&decl, |this| {
                 let body = this.lower_block(body, false);
                 this.expr_block(body, ThinVec::new())
+            }),
+        };
+
+        self.lower_body(|this| {
+            let mut arguments: Vec<hir::Arg> = Vec::new();
+            let mut statements: Vec<(hir::Stmt, Option<hir::Stmt>)> = Vec::new();
+
+            // 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 (index, argument) in decl.inputs.iter().enumerate() {
+                let argument = this.lower_arg(argument);
+                let span = argument.pat.span;
+
+                // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+                // `let <pat> = __argN;` statement. In this case, we do not rename the argument.
+                let (ident, is_simple_argument) = match argument.pat.node {
+                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) =>
+                        (ident, true),
+                    _ => {
+                        // Replace the ident for bindings that aren't simple.
+                        let name = format!("__arg{}", index);
+                        let ident = Ident::from_str(&name);
+
+                        (ident, false)
+                    },
+                };
+
+                // Construct an argument representing `__argN: <ty>` to replace the argument of the
+                // async function.
+                //
+                // If this is the simple case, this argument will end up being the same as the
+                // original argument, but with a different pattern id.
+                let new_argument_id = this.next_id();
+                let desugared_span =
+                    this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None);
+                let new_argument = hir::Arg {
+                    hir_id: argument.hir_id,
+                    pat: P(hir::Pat {
+                        hir_id: new_argument_id,
+                        node: hir::PatKind::Binding(hir::BindingAnnotation::Unannotated,
+                                                   new_argument_id, ident, None),
+                        span: desugared_span,
+                    }),
+                    source: hir::ArgSource::AsyncFn(argument.pat.hir_id),
+                };
+
+                let construct_stmt = |this: &mut LoweringContext<'_>, pat: P<hir::Pat>,
+                                      init_pat_id: hir::HirId| {
+                    hir::Stmt {
+                        hir_id: this.next_id(),
+                        node: hir::StmtKind::Local(P(hir::Local {
+                            pat,
+                            // We explicitly do not specify the type for any statements. 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 be valid in this binding. At the time of writing (13 Mar 19),
+                            // `impl_trait_in_bindings` is not stable.
+                            ty: None,
+                            init: Some(P(hir::Expr {
+                                span,
+                                node: hir::ExprKind::Path(hir::QPath::Resolved(None, P(hir::Path {
+                                    span,
+                                    res: Res::Local(init_pat_id),
+                                    segments: hir_vec![ hir::PathSegment::from_ident(ident) ],
+                                }))),
+                                attrs: ThinVec::new(),
+                                hir_id: this.next_id(),
+                            })),
+                            hir_id: this.next_id(),
+                            span: desugared_span,
+                            attrs: ThinVec::new(),
+                            source: hir::LocalSource::AsyncFn,
+                        })),
+                        span: desugared_span,
+                    }
+                };
+
+                let new_statements = if is_simple_argument {
+                    // If this is the simple case, then we only insert one statement that is
+                    // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+                    // `HirId`s are densely assigned.
+                    (construct_stmt(this, argument.pat, new_argument_id), None)
+                } else {
+                    // If this is not the simple case, then we construct two statements:
+                    //
+                    // ```
+                    // let __argN = __argN;
+                    // let <pat> = __argN;
+                    // ```
+                    //
+                    // The first statement moves the argument into the closure and thus ensures
+                    // that the drop order is correct.
+                    //
+                    // The second statement creates the bindings that the user wrote.
+
+                    // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+                    // because the user may have specified a `ref mut` binding in the next
+                    // statement.
+                    let hir_id = this.next_id();
+                    let move_stmt = construct_stmt(
+                        this,
+                        P(hir::Pat {
+                            hir_id,
+                            node: hir::PatKind::Binding(hir::BindingAnnotation::Mutable,
+                                                        hir_id, ident, None),
+                            span: desugared_span,
+                        }),
+                        new_argument_id,
+                    );
+
+                    // Construct the `let <pat> = __argN;` statement. We re-use the original
+                    // argument's pattern so that `HirId`s are densely assigned.
+                    let pattern_stmt = construct_stmt(this, argument.pat, hir_id);
+                    (move_stmt, Some(pattern_stmt))
+                };
+
+                arguments.push(new_argument);
+                statements.push(new_statements);
             }
+
+            let async_expr = this.make_async_expr(
+                CaptureBy::Value, closure_id, None, body.span,
+                |this| {
+                    let mut stmts = vec![];
+                    for (move_stmt, pattern_stmt) in statements.drain(..) {
+                        // Insert the `let __argN = __argN` statement first.
+                        stmts.push(move_stmt);
+                        // Then insert the `let <pat> = __argN` statement, if there is one.
+                        if let Some(pattern_stmt) = pattern_stmt {
+                            stmts.push(pattern_stmt);
+                        }
+                    }
+                    let body = this.lower_block_with_stmts(body, false, stmts);
+                    this.expr_block(body, ThinVec::new())
+                });
+            (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new()))
         })
     }
 
@@ -3049,7 +3208,6 @@ impl<'a> LoweringContext<'a> {
                 self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
             }
             ItemKind::Static(ref t, m, ref e) => {
-                let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemKind::Static(
                     self.lower_ty(
                         t,
@@ -3060,11 +3218,10 @@ impl<'a> LoweringContext<'a> {
                         }
                     ),
                     self.lower_mutability(m),
-                    value,
+                    self.lower_const_body(e),
                 )
             }
             ItemKind::Const(ref t, ref e) => {
-                let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemKind::Const(
                     self.lower_ty(
                         t,
@@ -3074,29 +3231,31 @@ impl<'a> LoweringContext<'a> {
                             ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                         }
                     ),
-                    value
+                    self.lower_const_body(e)
                 )
             }
             ItemKind::Fn(ref decl, header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
                 self.with_new_scopes(|this| {
+                    this.current_item = Some(ident.span);
+
                     // Note: we don't need to change the return type from `T` to
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
                     // declaration (decl), not the return types.
-                    let body_id = this.lower_async_body(decl, header.asyncness.node, body);
+                    let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body);
+
                     let (generics, fn_decl) = this.add_in_band_defs(
                         generics,
                         fn_def_id,
                         AnonymousLifetimeMode::PassThrough,
                         |this, idty| this.lower_fn_decl(
-                            decl,
+                            &decl,
                             Some((fn_def_id, idty)),
                             true,
                             header.asyncness.node.opt_return_id()
                         ),
                     );
-                    this.current_item = Some(ident.span);
 
                     hir::ItemKind::Fn(
                         fn_decl,
@@ -3478,7 +3637,7 @@ impl<'a> LoweringContext<'a> {
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
                     default
                         .as_ref()
-                        .map(|x| self.lower_body(None, |this| this.lower_expr(x))),
+                        .map(|x| self.lower_const_body(x)),
                 ),
             ),
             TraitItemKind::Method(ref sig, None) => {
@@ -3493,7 +3652,7 @@ impl<'a> LoweringContext<'a> {
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
             }
             TraitItemKind::Method(ref sig, Some(ref body)) => {
-                let body_id = self.lower_body(Some(&sig.decl), |this| {
+                let body_id = self.lower_fn_body(&sig.decl, |this| {
                     let body = this.lower_block(body, false);
                     this.expr_block(body, ThinVec::new())
                 });
@@ -3557,18 +3716,18 @@ impl<'a> LoweringContext<'a> {
         let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, node) = match i.node {
-            ImplItemKind::Const(ref ty, ref expr) => {
-                let body_id = self.lower_body(None, |this| this.lower_expr(expr));
-                (
-                    self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
-                    hir::ImplItemKind::Const(
-                        self.lower_ty(ty, ImplTraitContext::disallowed()),
-                        body_id,
-                    ),
-                )
-            }
+            ImplItemKind::Const(ref ty, ref expr) => (
+                self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
+                hir::ImplItemKind::Const(
+                    self.lower_ty(ty, ImplTraitContext::disallowed()),
+                    self.lower_const_body(expr),
+                ),
+            ),
             ImplItemKind::Method(ref sig, ref body) => {
-                let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness.node, body);
+                self.current_item = Some(i.span);
+                let body_id = self.lower_maybe_async_body(
+                    &sig.decl, sig.header.asyncness.node, body
+                );
                 let impl_trait_return_allow = !self.is_in_trait_impl;
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
@@ -3577,7 +3736,6 @@ impl<'a> LoweringContext<'a> {
                     impl_trait_return_allow,
                     sig.header.asyncness.node.opt_return_id(),
                 );
-                self.current_item = Some(i.span);
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
@@ -3973,7 +4131,7 @@ impl<'a> LoweringContext<'a> {
         self.with_new_scopes(|this| {
             hir::AnonConst {
                 hir_id: this.lower_node_id(c.id),
-                body: this.lower_body(None, |this| this.lower_expr(&c.value)),
+                body: this.lower_const_body(&c.value),
             }
         })
     }
@@ -4161,7 +4319,7 @@ impl<'a> LoweringContext<'a> {
 
                         // Transform `async |x: u8| -> X { ... }` into
                         // `|x: u8| future_from_generator(|| -> X { ... })`.
-                        let body_id = this.lower_body(Some(&outer_decl), |this| {
+                        let body_id = this.lower_fn_body(&outer_decl, |this| {
                             let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
                                 Some(&**ty)
                             } else { None };
@@ -4187,7 +4345,7 @@ impl<'a> LoweringContext<'a> {
                     self.with_new_scopes(|this| {
                         this.current_item = Some(fn_decl_span);
                         let mut is_generator = false;
-                        let body_id = this.lower_body(Some(decl), |this| {
+                        let body_id = this.lower_fn_body(decl, |this| {
                             let e = this.lower_expr(body);
                             is_generator = this.is_generator;
                             e
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 75799a19031..2d3de5af992 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -699,6 +699,19 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    /// Returns the `HirId` of this pattern, or, if this is an `async fn` desugaring, the `HirId`
+    /// of the original pattern that the user wrote.
+    pub fn original_pat_of_argument(&self, arg: &'hir Arg) -> &'hir Pat {
+        match &arg.source {
+            ArgSource::Normal => &*arg.pat,
+            ArgSource::AsyncFn(hir_id) => match self.find_by_hir_id(*hir_id) {
+                Some(Node::Pat(pat)) | Some(Node::Binding(pat)) => &pat,
+                Some(Node::Local(local)) => &*local.pat,
+                x => bug!("ArgSource::AsyncFn HirId not a pattern/binding/local: {:?}", x),
+            },
+        }
+    }
+
     pub fn is_const_scope(&self, hir_id: HirId) -> bool {
         self.walk_parent_nodes(hir_id, |node| match *node {
             Node::Item(Item { node: ItemKind::Const(_, _), .. }) => true,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 210c0c9225a..817c4cb540f 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1932,23 +1932,13 @@ pub struct Arg {
     pub source: ArgSource,
 }
 
-impl Arg {
-    /// Returns the pattern representing the original binding for this argument.
-    pub fn original_pat(&self) -> &P<Pat> {
-        match &self.source {
-            ArgSource::Normal => &self.pat,
-            ArgSource::AsyncFn(pat) => &pat,
-        }
-    }
-}
-
 /// Represents the source of an argument in a function header.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum ArgSource {
     /// Argument as specified by the user.
     Normal,
-    /// Generated argument from `async fn` lowering, contains the original binding pattern.
-    AsyncFn(P<Pat>),
+    /// Generated argument from `async fn` lowering, `HirId` is the original pattern.
+    AsyncFn(HirId),
 }
 
 /// Represents the header (not the body) of a function declaration.
diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 944cc8a8b19..46785f7ada1 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -86,12 +86,14 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
         let sub_is_ret_type =
             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
 
-        let span_label_var1 = match anon_arg_sup.original_pat().simple_ident() {
+        let arg_sup_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sup);
+        let span_label_var1 = match arg_sup_pat.simple_ident() {
             Some(simple_ident) => format!(" from `{}`", simple_ident),
             None => String::new(),
         };
 
-        let span_label_var2 = match anon_arg_sub.original_pat().simple_ident() {
+        let arg_sub_pat = self.tcx().hir().original_pat_of_argument(anon_arg_sub);
+        let span_label_var2 = match arg_sub_pat.simple_ident() {
             Some(simple_ident) => format!(" into `{}`", simple_ident),
             None => String::new(),
         };
diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 2d7587b11b6..1eb2af2bd58 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -95,7 +95,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
             }
         }
 
-        let (error_var, span_label_var) = match arg.original_pat().simple_ident() {
+        let arg_pat = self.tcx().hir().original_pat_of_argument(arg);
+        let (error_var, span_label_var) = match arg_pat.simple_ident() {
             Some(simple_ident) => (
                 format!("the type of `{}`", simple_ident),
                 format!("the type of `{}`", simple_ident),
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 593a09b6866..f48da4762b7 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2416,7 +2416,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 
             let help_name = if let Some(body) = parent {
                 let arg = &self.tcx.hir().body(body).arguments[index];
-                format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.original_pat().hir_id))
+                let original_pat = self.tcx.hir().original_pat_of_argument(arg);
+                format!("`{}`", self.tcx.hir().hir_to_pretty_string(original_pat.hir_id))
             } else {
                 format!("argument {}", index + 1)
             };
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 123b46cb048..a5d92d6c88f 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -84,11 +84,23 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
                     // HACK(eddyb) Avoid having RustCall on closures,
                     // as it adds unnecessary (and wrong) auto-tupling.
                     abi = Abi::Rust;
-                    Some(ArgInfo(liberated_closure_env_ty(tcx, id, body_id), None, None, None))
+                    Some(ArgInfo {
+                        ty: liberated_closure_env_ty(tcx, id, body_id),
+                        span: None,
+                        pattern: None,
+                        user_pattern: None,
+                        self_kind: None,
+                    })
                 }
                 ty::Generator(..) => {
                     let gen_ty = tcx.body_tables(body_id).node_type(id);
-                    Some(ArgInfo(gen_ty, None, None, None))
+                    Some(ArgInfo {
+                        ty: gen_ty,
+                        span: None,
+                        pattern: None,
+                        user_pattern: None,
+                        self_kind: None,
+                    })
                 }
                 _ => None,
             };
@@ -126,7 +138,15 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
                             opt_ty_info = None;
                             self_arg = None;
                         }
-                        ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg)
+
+                        let original_pat = tcx.hir().original_pat_of_argument(arg);
+                        ArgInfo {
+                            ty: fn_sig.inputs()[index],
+                            span: opt_ty_info,
+                            pattern: Some(&*arg.pat),
+                            user_pattern: Some(&original_pat),
+                            self_kind: self_arg,
+                        }
                     });
 
             let arguments = implicit_argument.into_iter().chain(explicit_arguments);
@@ -614,10 +634,13 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 ///////////////////////////////////////////////////////////////////////////
 /// the main entry point for building MIR for a function
 
-struct ArgInfo<'gcx>(Ty<'gcx>,
-                     Option<Span>,
-                     Option<&'gcx hir::Pat>,
-                     Option<ImplicitSelfKind>);
+struct ArgInfo<'gcx> {
+    ty: Ty<'gcx>,
+    span: Option<Span>,
+    pattern: Option<&'gcx hir::Pat>,
+    user_pattern: Option<&'gcx hir::Pat>,
+    self_kind: Option<ImplicitSelfKind>,
+}
 
 fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                    fn_id: hir::HirId,
@@ -878,26 +901,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                      -> BlockAnd<()>
     {
         // Allocate locals for the function arguments
-        for &ArgInfo(ty, _, pattern, _) in arguments.iter() {
+        for &ArgInfo { ty, span: _, pattern, user_pattern, self_kind: _ } in arguments.iter() {
             // If this is a simple binding pattern, give the local a name for
             // debuginfo and so that error reporting knows that this is a user
             // variable. For any other pattern the pattern introduces new
             // variables which will be named instead.
-            let mut name = None;
-            if let Some(pat) = pattern {
+            let (name, span) = if let Some(pat) = user_pattern {
                 match pat.node {
                     hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _)
-                    | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) => {
-                        name = Some(ident.name);
-                    }
-                    _ => (),
+                    | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) =>
+                        (Some(ident.name), pat.span),
+                    _ => (None, pattern.map_or(self.fn_span, |pat| pat.span))
                 }
-            }
-
-            let source_info = SourceInfo {
-                scope: OUTERMOST_SOURCE_SCOPE,
-                span: pattern.map_or(self.fn_span, |pat| pat.span)
+            } else {
+                (None, self.fn_span)
             };
+
+            let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, };
             self.local_decls.push(LocalDecl {
                 mutability: Mutability::Mut,
                 ty,
@@ -917,7 +937,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // Function arguments always get the first Local indices after the return place
             let local = Local::new(index + 1);
             let place = Place::Base(PlaceBase::Local(local));
-            let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info;
+            let &ArgInfo {
+                ty,
+                span: opt_ty_info,
+                pattern,
+                user_pattern: _,
+                self_kind: ref self_binding
+            } = arg_info;
 
             // Make sure we drop (parts of) the argument even when not matched on.
             self.schedule_drop(
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 20e18d60f07..f084d3b9f28 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -948,16 +948,6 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
 
         intravisit::walk_pat(self, pat);
     }
-
-    fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////
@@ -1147,16 +1137,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
         intravisit::walk_pat(self, pattern);
     }
 
-    fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
-
     fn visit_local(&mut self, local: &'tcx hir::Local) {
         if let Some(ref init) = local.init {
             if self.check_expr_pat_type(init.hir_id, init.span) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 82d198f0b78..3ada80b3e8b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1009,16 +1009,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
                 _: hir::BodyId, _: Span, _: hir::HirId) { }
-
-    fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 /// When `check_fn` is invoked on a generator (i.e., a body that
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index a535f776dfe..6f8682e6467 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -311,16 +311,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         let ty = self.resolve(&ty, &hir_ty.span);
         self.write_ty_to_tables(hir_ty.hir_id, ty);
     }
-
-    fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
-        match s {
-            // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
-            // a `NodeId` w/out a type, as it is only used for getting the name of the original
-            // pattern for diagnostics where only an `hir::Arg` is present.
-            hir::ArgSource::AsyncFn(..) => {},
-            _ => intravisit::walk_argument_source(self, s),
-        }
-    }
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e68ad6a7c3b..319adea6b86 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2018,8 +2018,9 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
 
         Arguments {
             values: self.0.iter().enumerate().map(|(i, ty)| {
+                let original_pat = cx.tcx.hir().original_pat_of_argument(&body.arguments[i]);
                 Argument {
-                    name: name_from_pat(&body.arguments[i].original_pat()),
+                    name: name_from_pat(original_pat),
                     type_: ty.clean(cx),
                 }
             }).collect()
diff --git a/src/test/ui/async-await/issues/issue-61187.rs b/src/test/ui/async-await/issues/issue-61187.rs
new file mode 100644
index 00000000000..8b939b43b8b
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-61187.rs
@@ -0,0 +1,9 @@
+// edition:2018
+#![feature(async_await)]
+
+fn main() {
+}
+
+async fn response(data: Vec<u8>) {
+    data.reverse(); //~ ERROR E0596
+}
diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr
new file mode 100644
index 00000000000..a0314226320
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-61187.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
+  --> $DIR/issue-61187.rs:8:5
+   |
+LL | async fn response(data: Vec<u8>) {
+   |                   ---- help: consider changing this to be mutable: `mut data`
+LL |     data.reverse();
+   |     ^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.