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 { + 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` 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, ) -> (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: ` argument to replace existing function argument `: `. + pub arg: Arg, + /// `let : = __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, }, 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 { + pub fn opt_return_id(&self) -> Option { 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, 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(nt: &mut token::Nonterminal, vis: pub fn noop_visit_asyncness(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, + mut asyncness: Spanned, constness: Spanned, 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, 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: ` 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 : = __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, 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, 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),