about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs6
-rw-r--r--src/librustc/hir/lowering.rs22
-rw-r--r--src/librustc/hir/map/def_collector.rs7
-rw-r--r--src/librustc/lint/context.rs16
-rw-r--r--src/librustc_passes/ast_validation.rs6
-rw-r--r--src/librustc_resolve/lib.rs10
-rw-r--r--src/librustc_save_analysis/sig.rs2
-rw-r--r--src/libsyntax/ast.rs29
-rw-r--r--src/libsyntax/ext/placeholders.rs20
-rw-r--r--src/libsyntax/mut_visit.rs10
-rw-r--r--src/libsyntax/parse/parser.rs73
-rw-r--r--src/libsyntax/print/pprust.rs23
12 files changed, 171 insertions, 53 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 007eaef74a7..b653093c1f8 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -58,10 +58,10 @@ impl<'a> FnKind<'a> {
         }
     }
 
-    pub fn header(&self) -> Option<FnHeader> {
+    pub fn header(&self) -> Option<&FnHeader> {
         match *self {
-            FnKind::ItemFn(_, _, header, _, _) => Some(header),
-            FnKind::Method(_, sig, _, _) => Some(sig.header),
+            FnKind::ItemFn(_, _, ref header, _, _) => Some(header),
+            FnKind::Method(_, ref sig, _, _) => Some(&sig.header),
             FnKind::Closure(_) => None,
         }
     }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e4cf3cfc63d..93a327588fe 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -3000,13 +3000,13 @@ impl<'a> LoweringContext<'a> {
     fn lower_async_body(
         &mut self,
         decl: &FnDecl,
-        asyncness: IsAsync,
+        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,
+                    CaptureBy::Value, *closure_id, None,
                     |this| {
                         let body = this.lower_block(body, false);
                         this.expr_block(body, ThinVec::new())
@@ -3067,14 +3067,14 @@ impl<'a> LoweringContext<'a> {
                     value
                 )
             }
-            ItemKind::Fn(ref decl, header, ref generics, ref body) => {
+            ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
                 self.with_new_scopes(|this| {
                     // 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_async_body(decl, &header.asyncness.node, body);
 
                     let (generics, fn_decl) = this.add_in_band_defs(
                         generics,
@@ -3565,7 +3565,7 @@ impl<'a> LoweringContext<'a> {
                 )
             }
             ImplItemKind::Method(ref sig, ref body) => {
-                let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness.node, body);
+                let body_id = self.lower_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,
@@ -3767,7 +3767,7 @@ impl<'a> LoweringContext<'a> {
         impl_trait_return_allow: bool,
         is_async: Option<NodeId>,
     ) -> (hir::Generics, hir::MethodSig) {
-        let header = self.lower_fn_header(sig.header);
+        let header = self.lower_fn_header(&sig.header);
         let (generics, decl) = self.add_in_band_defs(
             generics,
             fn_def_id,
@@ -3789,10 +3789,10 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+    fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
         hir::FnHeader {
             unsafety: self.lower_unsafety(h.unsafety),
-            asyncness: self.lower_asyncness(h.asyncness.node),
+            asyncness: self.lower_asyncness(&h.asyncness.node),
             constness: self.lower_constness(h.constness),
             abi: h.abi,
         }
@@ -3812,7 +3812,7 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
+    fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
         match a {
             IsAsync::Async { .. } => hir::IsAsync::Async,
             IsAsync::NotAsync => hir::IsAsync::NotAsync,
@@ -4125,7 +4125,7 @@ impl<'a> LoweringContext<'a> {
                 })
             }
             ExprKind::Closure(
-                capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
+                capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
             ) => {
                 if let IsAsync::Async { closure_id, .. } = asyncness {
                     let outer_decl = FnDecl {
@@ -4163,7 +4163,7 @@ impl<'a> LoweringContext<'a> {
                                 Some(&**ty)
                             } else { None };
                             let async_body = this.make_async_expr(
-                                capture_clause, closure_id, async_ret_ty,
+                                capture_clause, *closure_id, async_ret_ty,
                                 |this| {
                                     this.with_new_scopes(|this| this.lower_expr(body))
                                 });
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 1a3bbc5ecc4..6ba2a65703b 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -68,7 +68,7 @@ impl<'a> DefCollector<'a> {
         id: NodeId,
         name: Name,
         span: Span,
-        header: &FnHeader,
+        header: &'a FnHeader,
         generics: &'a Generics,
         decl: &'a FnDecl,
         body: &'a Block,
@@ -77,6 +77,7 @@ impl<'a> DefCollector<'a> {
             IsAsync::Async {
                 closure_id,
                 return_impl_trait_id,
+                ..
             } => (closure_id, return_impl_trait_id),
             _ => unreachable!(),
         };
@@ -290,7 +291,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
         match expr.node {
             ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
-            ExprKind::Closure(_, asyncness, ..) => {
+            ExprKind::Closure(_, ref asyncness, ..) => {
                 let closure_def = self.create_def(expr.id,
                                           DefPathData::ClosureExpr,
                                           REGULAR_SPACE,
@@ -300,7 +301,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                 // Async closures desugar to closures inside of closures, so
                 // we must create two defs.
                 if let IsAsync::Async { closure_id, .. } = asyncness {
-                    let async_def = self.create_def(closure_id,
+                    let async_def = self.create_def(*closure_id,
                                                     DefPathData::ClosureExpr,
                                                     REGULAR_SPACE,
                                                     expr.span);
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 4b615345a26..709e5c4cce4 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1328,6 +1328,22 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
 
         run_early_pass!(self, check_mac, mac);
     }
+
+    fn visit_fn_header(&mut self, header: &'a ast::FnHeader) {
+        // Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added
+        // to the function body and the arguments do not replace those in the declaration. They are
+        // still visited manually here so that buffered lints can be emitted.
+        if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
+            for a in arguments {
+                // Visit the argument..
+                self.visit_pat(&a.arg.pat);
+                self.visit_ty(&a.arg.ty);
+
+                // ..and the statement.
+                self.visit_stmt(&a.stmt);
+            }
+        }
+    }
 }
 
 struct LateLintPassObjects<'a> {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index a9a604cad8b..9dd8a7050fd 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -222,7 +222,7 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
+    fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) {
         if asyncness.is_async() {
             struct_span_err!(self.session, span, E0706,
                              "trait fns cannot be declared `async`").emit()
@@ -570,7 +570,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.invalid_visibility(&impl_item.vis, None);
                     if let ImplItemKind::Method(ref sig, _) = impl_item.node {
                         self.check_trait_fn_not_const(sig.header.constness);
-                        self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
+                        self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node);
                     }
                 }
             }
@@ -642,7 +642,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.no_questions_in_bounds(bounds, "supertraits", true);
                 for trait_item in trait_items {
                     if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
-                        self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
+                        self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node);
                         self.check_trait_fn_not_const(sig.header.constness);
                         if block.is_none() {
                             self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 8df83120738..de2f04035e4 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -817,13 +817,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         debug!("(resolving function) entering function");
         let (rib_kind, asyncness) = match function_kind {
             FnKind::ItemFn(_, ref header, ..) =>
-                (FnItemRibKind, header.asyncness.node),
+                (FnItemRibKind, &header.asyncness.node),
             FnKind::Method(_, ref sig, _, _) =>
-                (TraitOrImplItemRibKind, sig.header.asyncness.node),
+                (TraitOrImplItemRibKind, &sig.header.asyncness.node),
             FnKind::Closure(_) =>
                 // Async closures aren't resolved through `visit_fn`-- they're
                 // processed separately
-                (ClosureRibKind(node_id), IsAsync::NotAsync),
+                (ClosureRibKind(node_id), &IsAsync::NotAsync),
         };
 
         // Create a value rib for the function.
@@ -836,16 +836,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         let mut bindings_list = FxHashMap::default();
         for argument in &declaration.inputs {
             self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
-
             self.visit_ty(&argument.ty);
-
             debug!("(resolving function) recorded argument");
         }
         visit::walk_fn_ret_ty(self, &declaration.output);
 
         // Resolve the function body, potentially inside the body of an async closure
         if let IsAsync::Async { closure_id, .. } = asyncness {
-            let rib_kind = ClosureRibKind(closure_id);
+            let rib_kind = ClosureRibKind(*closure_id);
             self.ribs[ValueNS].push(Rib::new(rib_kind));
             self.label_ribs.push(Rib::new(rib_kind));
         }
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 76034f32c74..f9c1f02236d 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -374,7 +374,7 @@ impl Sig for ast::Item {
 
                 Ok(extend_sig(ty, text, defs, vec![]))
             }
-            ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
+            ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => {
                 let mut text = String::new();
                 if header.constness.node == ast::Constness::Const {
                     text.push_str("const ");
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 2fe0ebcdd28..e6669e0d6ed 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1849,18 +1849,35 @@ pub enum Unsafety {
     Normal,
 }
 
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+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,
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum IsAsync {
     Async {
         closure_id: NodeId,
         return_impl_trait_id: NodeId,
+        /// This field stores the arguments and statements that are used in HIR lowering to
+        /// ensure that `async fn` arguments are dropped at the correct time.
+        ///
+        /// The argument and statements here are generated at parse time as they are required in
+        /// both the hir lowering, def collection and name resolution and this stops them needing
+        /// to be created in each place.
+        arguments: Vec<AsyncArgument>,
     },
     NotAsync,
 }
 
 impl IsAsync {
-    pub fn is_async(self) -> bool {
-        if let IsAsync::Async { .. } = self {
+    pub fn is_async(&self) -> bool {
+        if let IsAsync::Async { .. } = *self {
             true
         } else {
             false
@@ -1868,12 +1885,12 @@ impl IsAsync {
     }
 
     /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
-    pub fn opt_return_id(self) -> Option<NodeId> {
+    pub fn opt_return_id(&self) -> Option<NodeId> {
         match self {
             IsAsync::Async {
                 return_impl_trait_id,
                 ..
-            } => Some(return_impl_trait_id),
+            } => Some(*return_impl_trait_id),
             IsAsync::NotAsync => None,
         }
     }
@@ -2213,7 +2230,7 @@ impl Item {
 ///
 /// All the information between the visibility and the name of the function is
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct FnHeader {
     pub unsafety: Unsafety,
     pub asyncness: Spanned<IsAsync>,
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 3e60dd81a3b..68cd3c28676 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -102,6 +102,13 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
     fn remove(&mut self, id: ast::NodeId) -> AstFragment {
         self.expanded_fragments.remove(&id).unwrap()
     }
+
+    fn next_id(&mut self, id: &mut ast::NodeId) {
+        if self.monotonic {
+            assert_eq!(*id, ast::DUMMY_NODE_ID);
+            *id = self.cx.resolver.next_node_id()
+        }
+    }
 }
 
 impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
@@ -183,9 +190,16 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
         noop_visit_block(block, self);
 
         for stmt in block.stmts.iter_mut() {
-            if self.monotonic {
-                assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
-                stmt.id = self.cx.resolver.next_node_id();
+            self.next_id(&mut stmt.id);
+        }
+    }
+
+    fn visit_asyncness(&mut self, a: &mut ast::IsAsync) {
+        noop_visit_asyncness(a, self);
+
+        if let ast::IsAsync::Async { ref mut arguments, .. } = a {
+            for argument in arguments.iter_mut() {
+                self.next_id(&mut argument.stmt.id);
             }
         }
     }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 87826ccc891..bb9116e678e 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -679,9 +679,17 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
 
 pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
     match asyncness {
-        IsAsync::Async { closure_id, return_impl_trait_id } => {
+        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() {
+                vis.visit_ident(ident);
+                vis.visit_arg(arg);
+                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 8620627765f..26ede5a1057 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1,4 +1,4 @@
-use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
+use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy};
 use crate::ast::{GenericBound, TraitBoundModifier};
 use crate::ast::Unsafety;
 use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
@@ -1517,6 +1517,7 @@ impl<'a> Parser<'a> {
             IsAsync::Async {
                 closure_id: ast::DUMMY_NODE_ID,
                 return_impl_trait_id: ast::DUMMY_NODE_ID,
+                arguments: Vec::new(),
             }
         } else {
             IsAsync::NotAsync
@@ -1575,7 +1576,7 @@ impl<'a> Parser<'a> {
             // trait item macro.
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
-            let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
+            let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
 
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
@@ -1589,6 +1590,7 @@ impl<'a> Parser<'a> {
                 p.parse_arg_general(p.span.rust_2018(), true, false)
             })?;
             generics.where_clause = self.parse_where_clause()?;
+            self.construct_async_arguments(&mut asyncness, &d);
 
             let sig = ast::MethodSig {
                 header: FnHeader {
@@ -6567,7 +6569,7 @@ impl<'a> Parser<'a> {
     /// Parses an item-position function declaration.
     fn parse_item_fn(&mut self,
                      unsafety: Unsafety,
-                     asyncness: Spanned<IsAsync>,
+                     mut asyncness: Spanned<IsAsync>,
                      constness: Spanned<Constness>,
                      abi: Abi)
                      -> PResult<'a, ItemInfo> {
@@ -6576,6 +6578,7 @@ impl<'a> Parser<'a> {
         let decl = self.parse_fn_decl(allow_c_variadic)?;
         generics.where_clause = self.parse_where_clause()?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+        self.construct_async_arguments(&mut asyncness, &decl);
         let header = FnHeader { unsafety, asyncness, constness, abi };
         Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
     }
@@ -6751,11 +6754,12 @@ impl<'a> Parser<'a> {
             Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
                 ast::ImplItemKind::Macro(mac)))
         } else {
-            let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
+            let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
             let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
             generics.where_clause = self.parse_where_clause()?;
+            self.construct_async_arguments(&mut asyncness, &decl);
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
             let header = ast::FnHeader { abi, unsafety, constness, asyncness };
@@ -8177,6 +8181,7 @@ impl<'a> Parser<'a> {
                                    respan(async_span, IsAsync::Async {
                                        closure_id: ast::DUMMY_NODE_ID,
                                        return_impl_trait_id: ast::DUMMY_NODE_ID,
+                                       arguments: Vec::new(),
                                    }),
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
@@ -8822,6 +8827,66 @@ impl<'a> Parser<'a> {
             }
         }
     }
+
+    /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
+    /// into the generated closure so that they are dropped when the future is polled and not when
+    /// it is created.
+    ///
+    /// The arguments of the function are replaced in HIR lowering with the arguments created by
+    /// this function and the statements created here are inserted at the top of the closure body.
+    fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &FnDecl) {
+        if let IsAsync::Async { ref mut arguments, .. } = asyncness.node {
+            for (index, input) in decl.inputs.iter().enumerate() {
+                let id = ast::DUMMY_NODE_ID;
+                let span = input.pat.span;
+
+                // Construct a name for our temporary argument.
+                let name = format!("__arg{}", index);
+                let ident = Ident::from_str(&name);
+
+                // Construct an argument representing `__argN: <ty>` to replace the argument of the
+                // async function.
+                let arg = Arg {
+                    ty: input.ty.clone(),
+                    id,
+                    pat: P(Pat {
+                        id,
+                        node: PatKind::Ident(
+                            BindingMode::ByValue(Mutability::Immutable), ident, None,
+                        ),
+                        span,
+                    }),
+                };
+
+                // Construct a `let <pat>: <ty> = __argN;` statement to insert at the top of the
+                // async closure.
+                let local = P(Local {
+                    pat: input.pat.clone(),
+                    ty: Some(P(Ty {
+                        id,
+                        node: input.ty.node.clone(),
+                        span: input.ty.span,
+                    })),
+                    init: Some(P(Expr {
+                        id,
+                        node: ExprKind::Path(None, ast::Path {
+                            span,
+                            segments: vec![PathSegment { ident, id, args: None }],
+                        }),
+                        span,
+                        attrs: ThinVec::new(),
+                    })),
+                    id,
+                    span,
+                    attrs: ThinVec::new(),
+                    source: LocalSource::AsyncFn,
+                });
+                let stmt = Stmt { id, node: StmtKind::Local(local), span, };
+
+                arguments.push(AsyncArgument { ident, arg, stmt });
+            }
+        }
+    }
 }
 
 pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index ca05ff71c94..d440a02f2fd 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -372,7 +372,7 @@ pub fn vis_to_string(v: &ast::Visibility) -> String {
 }
 
 pub fn fun_to_string(decl: &ast::FnDecl,
-                     header: ast::FnHeader,
+                     header: &ast::FnHeader,
                      name: ast::Ident,
                      generics: &ast::Generics)
                      -> String {
@@ -1133,7 +1133,7 @@ impl<'a> State<'a> {
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                 self.head("")?;
-                self.print_fn(decl, ast::FnHeader::default(),
+                self.print_fn(decl, &ast::FnHeader::default(),
                               Some(item.ident),
                               generics, &item.vis)?;
                 self.end()?; // end head-ibox
@@ -1263,7 +1263,7 @@ impl<'a> State<'a> {
                 self.s.word(";")?;
                 self.end()?; // end the outer cbox
             }
-            ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => {
+            ast::ItemKind::Fn(ref decl, ref header, ref param_names, ref body) => {
                 self.head("")?;
                 self.print_fn(
                     decl,
@@ -1615,7 +1615,7 @@ impl<'a> State<'a> {
                             vis: &ast::Visibility)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
-                      m.header,
+                      &m.header,
                       Some(ident),
                       &generics,
                       vis)
@@ -2213,7 +2213,7 @@ impl<'a> State<'a> {
                 self.bclose_(expr.span, INDENT_UNIT)?;
             }
             ast::ExprKind::Closure(
-                capture_clause, asyncness, movability, ref decl, ref body, _) => {
+                capture_clause, ref asyncness, movability, ref decl, ref body, _) => {
                 self.print_movability(movability)?;
                 self.print_asyncness(asyncness)?;
                 self.print_capture_clause(capture_clause)?;
@@ -2798,7 +2798,7 @@ impl<'a> State<'a> {
 
     pub fn print_fn(&mut self,
                     decl: &ast::FnDecl,
-                    header: ast::FnHeader,
+                    header: &ast::FnHeader,
                     name: Option<ast::Ident>,
                     generics: &ast::Generics,
                     vis: &ast::Visibility) -> io::Result<()> {
@@ -2853,8 +2853,7 @@ impl<'a> State<'a> {
         }
     }
 
-    pub fn print_asyncness(&mut self, asyncness: ast::IsAsync)
-                                -> io::Result<()> {
+    pub fn print_asyncness(&mut self, asyncness: &ast::IsAsync) -> io::Result<()> {
         if asyncness.is_async() {
             self.word_nbsp("async")?;
         }
@@ -3126,7 +3125,7 @@ impl<'a> State<'a> {
             span: syntax_pos::DUMMY_SP,
         };
         self.print_fn(decl,
-                      ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
+                      &ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
                       name,
                       &generics,
                       &source_map::dummy_spanned(ast::VisibilityKind::Inherited))?;
@@ -3189,7 +3188,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_fn_header_info(&mut self,
-                                header: ast::FnHeader,
+                                header: &ast::FnHeader,
                                 vis: &ast::Visibility) -> io::Result<()> {
         self.s.word(visibility_qualified(vis, ""))?;
 
@@ -3198,7 +3197,7 @@ impl<'a> State<'a> {
             ast::Constness::Const => self.word_nbsp("const")?
         }
 
-        self.print_asyncness(header.asyncness.node)?;
+        self.print_asyncness(&header.asyncness.node)?;
         self.print_unsafety(header.unsafety)?;
 
         if header.abi != Abi::Rust {
@@ -3247,7 +3246,7 @@ mod tests {
             assert_eq!(
                 fun_to_string(
                     &decl,
-                    ast::FnHeader {
+                    &ast::FnHeader {
                         unsafety: ast::Unsafety::Normal,
                         constness: source_map::dummy_spanned(ast::Constness::NotConst),
                         asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync),