From 6c73b952e0b251fbba90262381225e52ff2ecd3a Mon Sep 17 00:00:00 2001 From: Without Boats Date: Wed, 16 May 2018 22:55:18 -0700 Subject: [PATCH 1/7] Parse async fn header. This is gated on edition 2018 & the `async_await` feature gate. The parser will accept `async fn` and `async unsafe fn` as fn items. Along the same lines as `const fn`, only `async unsafe fn` is permitted, not `unsafe async fn`.The parser will not accept `async` functions as trait methods. To do a little code clean up, four fields of the function type struct have been merged into the new `FnHeader` struct: constness, asyncness, unsafety, and ABI. Also, a small bug in HIR printing is fixed: it previously printed `const unsafe fn` as `unsafe const fn`, which is grammatically incorrect. --- src/doc/book | 2 +- src/librustc/hir/intravisit.rs | 9 ++-- src/librustc/hir/lowering.rs | 26 ++++++--- src/librustc/hir/map/blocks.rs | 39 ++++++-------- src/librustc/hir/map/mod.rs | 2 +- src/librustc/hir/mod.rs | 35 +++++++++--- src/librustc/hir/print.rs | 45 ++++++++-------- src/librustc/ich/impls_hir.rs | 17 ++++-- src/librustc/middle/reachable.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc_allocator/expand.rs | 12 ++--- src/librustc_driver/pretty.rs | 12 ++--- src/librustc_lint/bad_style.rs | 4 +- src/librustc_lint/builtin.rs | 6 +-- src/librustc_metadata/encoder.rs | 12 ++--- src/librustc_mir/transform/check_unsafety.rs | 4 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_save_analysis/sig.rs | 24 +++++---- src/librustc_typeck/collect.rs | 10 ++-- src/librustdoc/clean/inline.rs | 9 ++-- src/librustdoc/clean/mod.rs | 48 ++++++++--------- src/librustdoc/doctree.rs | 5 +- src/librustdoc/html/render.rs | 37 ++++++------- src/librustdoc/visit_ast.rs | 14 ++--- src/libsyntax/ast.rs | 37 +++++++++++-- src/libsyntax/ext/build.rs | 9 ++-- src/libsyntax/feature_gate.rs | 40 ++++++++------ src/libsyntax/fold.rs | 8 ++- src/libsyntax/parse/mod.rs | 13 +++-- src/libsyntax/parse/parser.rs | 57 +++++++++++++++----- src/libsyntax/print/pprust.rs | 47 +++++++--------- src/libsyntax/test.rs | 20 ++++--- src/libsyntax/visit.rs | 12 ++--- src/libsyntax_ext/deriving/generic/mod.rs | 10 ++-- src/llvm | 2 +- src/tools/cargo | 2 +- src/tools/clippy | 2 +- src/tools/rls | 2 +- src/tools/rustfmt | 2 +- 39 files changed, 366 insertions(+), 279 deletions(-) diff --git a/src/doc/book b/src/doc/book index 36d65d00164d1..f51127530d46b 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 36d65d00164d1750f6fa7f8b0f52dabc3fea500b +Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3 diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2ef022cecdf49..c65a85a8357fe 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -41,7 +41,6 @@ //! This order consistency is required in a few places in rustc, for //! example generator inference, and possibly also HIR borrowck. -use rustc_target::spec::abi::Abi; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax_pos::Span; use hir::*; @@ -55,7 +54,7 @@ use std::u32; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, &'a Visibility, &'a [Attribute]), + ItemFn(Name, &'a Generics, FnHeader, &'a Visibility, &'a [Attribute]), /// fn foo(&self) Method(Name, &'a MethodSig, Option<&'a Visibility>, &'a [Attribute]), @@ -466,12 +465,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ty(typ); visitor.visit_nested_body(body); } - ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => { + ItemFn(ref declaration, header, ref generics, body_id) => { visitor.visit_fn(FnKind::ItemFn(item.name, generics, - unsafety, - constness, - abi, + header, &item.vis, &item.attrs), declaration, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d20cea8331fdd..a2eae6502ee37 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2194,7 +2194,7 @@ impl<'a> LoweringContext<'a> { let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value) } - ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + 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| { let body_id = this.lower_body(Some(decl), |this| { @@ -2210,9 +2210,7 @@ impl<'a> LoweringContext<'a> { hir::ItemFn( fn_decl, - this.lower_unsafety(unsafety), - this.lower_constness(constness), - abi, + this.lower_fn_header(header), generics, body_id, ) @@ -2750,9 +2748,7 @@ impl<'a> LoweringContext<'a> { impl_trait_return_allow: bool, ) -> hir::MethodSig { hir::MethodSig { - abi: sig.abi, - unsafety: self.lower_unsafety(sig.unsafety), - constness: self.lower_constness(sig.constness), + header: self.lower_fn_header(sig.header), decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow), } } @@ -2764,6 +2760,15 @@ impl<'a> LoweringContext<'a> { } } + fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { + hir::FnHeader { + unsafety: self.lower_unsafety(h.unsafety), + asyncness: self.lower_asyncness(h.asyncness), + constness: self.lower_constness(h.constness), + abi: h.abi, + } + } + fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { match u { Unsafety::Unsafe => hir::Unsafety::Unsafe, @@ -2778,6 +2783,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync { + match a { + IsAsync::Async => hir::IsAsync::Async, + IsAsync::NotAsync => hir::IsAsync::NotAsync, + } + } + fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { match u { UnOp::Deref => hir::UnDeref, diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 362c0bf07f73b..f665ced3dbcf1 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -25,7 +25,6 @@ use hir as ast; use hir::map::{self, Node}; use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; -use rustc_target::spec::abi; use syntax::ast::{Attribute, Name, NodeId}; use syntax_pos::Span; @@ -105,9 +104,7 @@ impl<'a> Code<'a> { struct ItemFnParts<'a> { name: Name, decl: &'a ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: abi::Abi, + header: ast::FnHeader, vis: &'a ast::Visibility, generics: &'a ast::Generics, body: ast::BodyId, @@ -183,31 +180,31 @@ impl<'a> FnLikeNode<'a> { pub fn constness(self) -> ast::Constness { match self.kind() { - FnKind::ItemFn(_, _, _, constness, ..) => { - constness - } - FnKind::Method(_, m, ..) => { - m.constness - } + FnKind::ItemFn(_, _, header, ..) => header.constness, + FnKind::Method(_, m, ..) => m.header.constness, _ => ast::Constness::NotConst } } + pub fn asyncness(self) -> ast::IsAsync { + match self.kind() { + FnKind::ItemFn(_, _, header, ..) => header.asyncness, + FnKind::Method(_, m, ..) => m.header.asyncness, + _ => ast::IsAsync::NotAsync + } + } + pub fn unsafety(self) -> ast::Unsafety { match self.kind() { - FnKind::ItemFn(_, _, unsafety, ..) => { - unsafety - } - FnKind::Method(_, m, ..) => { - m.unsafety - } + FnKind::ItemFn(_, _, header, ..) => header.unsafety, + FnKind::Method(_, m, ..) => m.header.unsafety, _ => ast::Unsafety::Normal } } pub fn kind(self) -> FnKind<'a> { let item = |p: ItemFnParts<'a>| -> FnKind<'a> { - FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs) + FnKind::ItemFn(p.name, p.generics, p.header, p.vis, p.attrs) }; let closure = |c: ClosureParts<'a>| { FnKind::Closure(c.attrs) @@ -232,19 +229,17 @@ impl<'a> FnLikeNode<'a> { { match self.node { map::NodeItem(i) => match i.node { - ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, block) => + ast::ItemFn(ref decl, header, ref generics, block) => item_fn(ItemFnParts { id: i.id, name: i.name, decl: &decl, - unsafety, body: block, - generics, - abi, vis: &i.vis, - constness, span: i.span, attrs: &i.attrs, + header, + generics, }), _ => bug!("item FnLikeNode that is not fn-like"), }, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 951bb6ad1501b..59c4166b7eaa5 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -176,7 +176,7 @@ impl<'hir> MapEntry<'hir> { match item.node { ItemConst(_, body) | ItemStatic(.., body) | - ItemFn(_, _, _, _, _, body) => Some(body), + ItemFn(_, _, _, body) => Some(body), _ => None, } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7db77a3e4afa5..d5f1fb046388a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1558,9 +1558,7 @@ pub struct MutTy { /// Represents a method's signature in a trait declaration or implementation. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { - pub unsafety: Unsafety, - pub constness: Constness, - pub abi: Abi, + pub header: FnHeader, pub decl: P, } @@ -1787,7 +1785,13 @@ pub enum IsAuto { No } -#[derive(Copy, Clone, PartialEq, Eq,PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum IsAsync { + Async, + NotAsync, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, Normal, @@ -2063,6 +2067,25 @@ pub struct Item { pub span: Span, } +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct FnHeader { + pub unsafety: Unsafety, + pub constness: Constness, + pub asyncness: IsAsync, + pub abi: Abi, +} + +impl Default for FnHeader { + fn default() -> FnHeader { + FnHeader { + unsafety: Unsafety::Normal, + constness: Constness::NotConst, + asyncness: IsAsync::NotAsync, + abi: Abi::Rust, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Item_ { /// An `extern crate` item, with optional *original* crate name if the crate was renamed. @@ -2082,7 +2105,7 @@ pub enum Item_ { /// A `const` item ItemConst(P, BodyId), /// A function declaration - ItemFn(P, Unsafety, Constness, Abi, Generics, BodyId), + ItemFn(P, FnHeader, Generics, BodyId), /// A module ItemMod(Mod), /// An external module @@ -2144,7 +2167,7 @@ impl Item_ { pub fn generics(&self) -> Option<&Generics> { Some(match *self { - ItemFn(_, _, _, _, ref generics, _) | + ItemFn(_, _, ref generics, _) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 8173ec48045c3..dad6db67237fb 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -446,9 +446,7 @@ impl<'a> State<'a> { hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => { self.head("")?; self.print_fn(decl, - hir::Unsafety::Normal, - hir::Constness::NotConst, - Abi::Rust, + hir::FnHeader::default(), Some(item.name), generics, &item.vis, @@ -585,12 +583,10 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => { + hir::ItemFn(ref decl, header, ref typarams, body) => { self.head("")?; self.print_fn(decl, - unsafety, - constness, - abi, + header, Some(item.name), typarams, &item.vis, @@ -887,9 +883,7 @@ impl<'a> State<'a> { body_id: Option) -> io::Result<()> { self.print_fn(&m.decl, - m.unsafety, - m.constness, - m.abi, + m.header, Some(name), generics, vis, @@ -1924,16 +1918,14 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - abi: Abi, + header: hir::FnHeader, name: Option, generics: &hir::Generics, vis: &hir::Visibility, arg_names: &[Spanned], body_id: Option) -> io::Result<()> { - self.print_fn_header_info(unsafety, constness, abi, vis)?; + self.print_fn_header_info(header, vis)?; if let Some(name) = name { self.nbsp()?; @@ -2189,9 +2181,10 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - unsafety, - hir::Constness::NotConst, - abi, + hir::FnHeader { + unsafety, abi, + ..hir::FnHeader::default() + }, name, &generics, &hir::Inherited, @@ -2262,22 +2255,26 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - unsafety: hir::Unsafety, - constness: hir::Constness, - abi: Abi, + header: hir::FnHeader, vis: &hir::Visibility) -> io::Result<()> { self.s.word(&visibility_qualified(vis, ""))?; - self.print_unsafety(unsafety)?; - match constness { + match header.constness { hir::Constness::NotConst => {} hir::Constness::Const => self.word_nbsp("const")?, } - if abi != Abi::Rust { + match header.asyncness { + hir::IsAsync::NotAsync => {} + hir::IsAsync::Async => self.word_nbsp("async")?, + } + + self.print_unsafety(header.unsafety)?; + + if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string())?; + self.word_nbsp(&header.abi.to_string())?; } self.s.word("fn") diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 21c1af919de9a..80c3613b2b696 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -260,9 +260,7 @@ impl_stable_hash_for!(struct hir::MutTy { }); impl_stable_hash_for!(struct hir::MethodSig { - unsafety, - constness, - abi, + header, decl }); @@ -273,6 +271,13 @@ impl_stable_hash_for!(struct hir::TypeBinding { span }); +impl_stable_hash_for!(struct hir::FnHeader { + unsafety, + constness, + asyncness, + abi +}); + impl<'a> HashStable> for hir::Ty { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -877,7 +882,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemUse(path, use_kind), ItemStatic(ty, mutability, body_id), ItemConst(ty, body_id), - ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemFn(fn_decl, header, generics, body_id), ItemMod(module), ItemForeignMod(foreign_mod), ItemGlobalAsm(global_asm), @@ -1078,6 +1083,10 @@ impl_stable_hash_for!(enum hir::Unsafety { Normal }); +impl_stable_hash_for!(enum hir::IsAsync { + Async, + NotAsync +}); impl_stable_hash_for!(enum hir::Constness { Const, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 249651ef65da0..bddd1ecc9654f 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -227,8 +227,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // If we are building an executable, only explicitly extern // types need to be exported. if let hir_map::NodeItem(item) = *node { - let reachable = if let hir::ItemFn(.., abi, _, _) = item.node { - abi != Abi::Rust + let reachable = if let hir::ItemFn(_, header, ..) = item.node { + header.abi != Abi::Rust } else { false }; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 966000ccd908a..ad07cf4d2f23d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { - hir::ItemFn(ref decl, _, _, _, ref generics, _) => { + hir::ItemFn(ref decl, _, ref generics, _) => { self.visit_early_late(None, decl, generics, |this| { intravisit::walk_item(this, item); }); diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 497d5fdcac702..e0c3a6a429f2e 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -10,12 +10,11 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; -use rustc_target::spec::abi::Abi; use syntax::ast::{Attribute, Crate, LitKind, StrStyle}; -use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety}; +use syntax::ast::{Arg, FnHeader, Generics, Mac, Mutability, Ty, Unsafety}; use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}; use syntax::attr; -use syntax::codemap::{dummy_spanned, respan}; +use syntax::codemap::respan; use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan}; use syntax::ext::base::ExtCtxt; use syntax::ext::base::Resolver; @@ -152,9 +151,10 @@ impl<'a> AllocFnFactory<'a> { let (output_ty, output_expr) = self.ret_ty(&method.output, result); let kind = ItemKind::Fn( self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), - Unsafety::Unsafe, - dummy_spanned(Constness::NotConst), - Abi::Rust, + FnHeader { + unsafety: Unsafety::Unsafe, + ..FnHeader::default() + }, Generics::default(), self.cx.block_expr(output_expr), ); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index f1ad14237eec2..5b42bec8b2a02 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -706,8 +706,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { let is_const = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, - ast::ItemKind::Fn(ref decl, _, ref constness, _, _, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ItemKind::Fn(ref decl, ref header, _, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) @@ -716,8 +716,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector { let is_const = match i.node { ast::TraitItemKind::Const(..) => true, - ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) @@ -726,8 +726,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector { let is_const = match i.node { ast::ImplItemKind::Const(..) => true, - ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 651a2e187f6b4..bfbabc4cf0b1b 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -282,9 +282,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { _ => (), } } - FnKind::ItemFn(name, _, _, _, abi, _, attrs) => { + FnKind::ItemFn(name, _, header, _, attrs) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() { + if header.abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() { return; } self.check_snake_case(cx, "function", &name.as_str(), Some(span)) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5951fd478d89f..4c3e0fe39ded0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -258,12 +258,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { span: Span, _: ast::NodeId) { match fk { - FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => { + FnKind::ItemFn(_, _, hir::FnHeader { unsafety: hir::Unsafety::Unsafe, .. }, ..) => { self.report_unsafe(cx, span, "declaration of an `unsafe` function") } FnKind::Method(_, sig, ..) => { - if sig.unsafety == hir::Unsafety::Unsafe { + if sig.header.unsafety == hir::Unsafety::Unsafe { self.report_unsafe(cx, span, "implementation of an `unsafe` method") } } @@ -274,7 +274,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode { fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) { if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node { - if sig.unsafety == hir::Unsafety::Unsafe { + if sig.header.unsafety == hir::Unsafety::Unsafe { self.report_unsafe(cx, item.span, "declaration of an `unsafe` method") } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ab30ff7f072b7..da8c2374aa603 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -917,7 +917,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { FnData { - constness: sig.constness, + constness: sig.header.constness, arg_names: self.encode_fn_arg_names_for_body(body), sig: self.lazy(&tcx.fn_sig(def_id)), } @@ -941,7 +941,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let needs_inline = (generics.requires_monomorphization(self.tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) && !self.metadata_output_only(); - let is_const_fn = sig.constness == hir::Constness::Const; + let is_const_fn = sig.header.constness == hir::Constness::Const; let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; needs_inline || is_const_fn || always_encode_mir }, @@ -1045,9 +1045,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.encode_rendered_const_for_body(body_id) ) } - hir::ItemFn(_, _, constness, .., body) => { + hir::ItemFn(_, header, .., body) => { let data = FnData { - constness, + constness: header.constness, arg_names: self.encode_fn_arg_names_for_body(body), sig: self.lazy(&tcx.fn_sig(def_id)), }; @@ -1231,13 +1231,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.encode_optimized_mir(def_id) } hir::ItemConst(..) => self.encode_optimized_mir(def_id), - hir::ItemFn(_, _, constness, _, ref generics, _) => { + hir::ItemFn(_, header, ref generics, _) => { let has_tps = generics.ty_params().next().is_some(); let needs_inline = (has_tps || tcx.codegen_fn_attrs(def_id).requests_inline()) && !self.metadata_output_only(); let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; - if needs_inline || constness == hir::Constness::Const || always_encode_mir { + if needs_inline || header.constness == hir::Constness::Const || always_encode_mir { self.encode_optimized_mir(def_id) } else { None diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index fc3764e4f49a5..0eacb2034cdf9 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -379,10 +379,10 @@ fn is_enclosed(tcx: TyCtxt, if used_unsafe.contains(&parent_id) { Some(("block".to_string(), parent_id)) } else if let Some(hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(_, fn_unsafety, _, _, _, _), + node: hir::ItemFn(_, header, _, _), .. })) = tcx.hir.find(parent_id) { - match fn_unsafety { + match header.unsafety { hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), hir::Unsafety::Normal => None, } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 4f239a0868ebf..d55825413e03d 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -257,7 +257,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { - self.check_trait_fn_not_const(sig.constness); + self.check_trait_fn_not_const(sig.header.constness); } } } @@ -309,7 +309,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_const(sig.constness); + self.check_trait_fn_not_const(sig.header.constness); if block.is_none() { self.check_decl_no_pat(&sig.decl, |span, mut_ident| { if mut_ident { diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index e3545e8f1a9b8..0adbcc9a8103e 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -380,17 +380,20 @@ impl Sig for ast::Item { Ok(extend_sig(ty, text, defs, vec![])) } - ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, _) => { + ast::ItemKind::Fn(ref decl, header, ref generics, _) => { let mut text = String::new(); - if constness.node == ast::Constness::Const { + if header.constness.node == ast::Constness::Const { text.push_str("const "); } - if unsafety == ast::Unsafety::Unsafe { + if header.asyncness == ast::IsAsync::Async { + text.push_str("async "); + } + if header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if abi != ::rustc_target::spec::abi::Abi::Rust { + if header.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); - text.push_str(&abi.to_string()); + text.push_str(&header.abi.to_string()); text.push(' '); } text.push_str("fn "); @@ -925,15 +928,18 @@ fn make_method_signature( ) -> Result { // FIXME code dup with function signature let mut text = String::new(); - if m.constness.node == ast::Constness::Const { + if m.header.constness.node == ast::Constness::Const { text.push_str("const "); } - if m.unsafety == ast::Unsafety::Unsafe { + if m.header.asyncness == ast::IsAsync::Async { + text.push_str("async "); + } + if m.header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if m.abi != ::rustc_target::spec::abi::Abi::Rust { + if m.header.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); - text.push_str(&m.abi.to_string()); + text.push_str(&m.header.abi.to_string()); text.push(' '); } text.push_str("fn "); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d0d147b8e85cd..12e93ce00fe7f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1146,13 +1146,13 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let icx = ItemCtxt::new(tcx, def_id); match tcx.hir.get(node_id) { - NodeTraitItem(&hir::TraitItem { node: TraitItemKind::Method(ref sig, _), .. }) | - NodeImplItem(&hir::ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) => { - AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl) + NodeTraitItem(hir::TraitItem { node: TraitItemKind::Method(sig, _), .. }) | + NodeImplItem(hir::ImplItem { node: ImplItemKind::Method(sig, _), .. }) => { + AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl) } - NodeItem(&hir::Item { node: ItemFn(ref decl, unsafety, _, abi, _, _), .. }) => { - AstConv::ty_of_fn(&icx, unsafety, abi, decl) + NodeItem(hir::Item { node: ItemFn(decl, header, _, _), .. }) => { + AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl) } NodeForeignItem(&hir::ForeignItem { node: ForeignItemFn(ref fn_decl, _, _), .. }) => { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f112f3ca2ae53..4c0cbfc954fd7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -181,9 +181,12 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { clean::Function { decl: (did, sig).clean(cx), generics: (cx.tcx.generics_of(did), &predicates).clean(cx), - unsafety: sig.unsafety(), - constness, - abi: sig.abi(), + header: hir::FnHeader { + unsafety: sig.unsafety(), + abi: sig.abi(), + constness, + ..hir::FnHeader::default() + } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d4c1ba63a8c98..d44eb52dc9138 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -19,8 +19,8 @@ pub use self::SelfTy::*; pub use self::FunctionRetTy::*; pub use self::Visibility::{Public, Inherited}; -use syntax; use rustc_target::spec::abi::Abi; +use syntax; use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; use syntax::codemap::{dummy_spanned, Spanned}; @@ -1901,10 +1901,8 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Method { pub generics: Generics, - pub unsafety: hir::Unsafety, - pub constness: hir::Constness, pub decl: FnDecl, - pub abi: Abi, + pub header: hir::FnHeader, } impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) { @@ -1915,28 +1913,23 @@ impl<'a> Clean for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) Method { decl, generics, - unsafety: self.0.unsafety, - constness: self.0.constness, - abi: self.0.abi + header: self.0.header, } } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct TyMethod { - pub unsafety: hir::Unsafety, + pub header: hir::FnHeader, pub decl: FnDecl, pub generics: Generics, - pub abi: Abi, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Function { pub decl: FnDecl, pub generics: Generics, - pub unsafety: hir::Unsafety, - pub constness: hir::Constness, - pub abi: Abi, + pub header: hir::FnHeader, } impl Clean for doctree::Function { @@ -1955,9 +1948,7 @@ impl Clean for doctree::Function { inner: FunctionItem(Function { decl, generics, - unsafety: self.unsafety, - constness: self.constness, - abi: self.abi, + header: self.header, }), } } @@ -2186,10 +2177,9 @@ impl Clean for hir::TraitItem { (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) }); TyMethodItem(TyMethod { - unsafety: sig.unsafety.clone(), + header: sig.header, decl, generics, - abi: sig.abi }) } hir::TraitItemKind::Type(ref bounds, ref default) => { @@ -2288,18 +2278,24 @@ impl<'tcx> Clean for ty::AssociatedItem { hir::Constness::NotConst }; MethodItem(Method { - unsafety: sig.unsafety(), generics, decl, - abi: sig.abi(), - constness, + header: hir::FnHeader { + unsafety: sig.unsafety(), + abi: sig.abi(), + constness, + ..hir::FnHeader::default() + } }) } else { TyMethodItem(TyMethod { - unsafety: sig.unsafety(), generics, decl, - abi: sig.abi(), + header: hir::FnHeader { + unsafety: sig.unsafety(), + abi: sig.abi(), + ..hir::FnHeader::default() + } }) } } @@ -3485,9 +3481,9 @@ impl Clean for hir::BareFnTy { }); BareFunctionDecl { unsafety: self.unsafety, + abi: self.abi, decl, generic_params, - abi: self.abi, } } } @@ -3775,7 +3771,7 @@ impl Clean> for hir::ForeignMod { let mut items = self.items.clean(cx); for item in &mut items { if let ForeignFunctionItem(ref mut f) = item.inner { - f.abi = self.abi; + f.header.abi = self.abi; } } items @@ -3792,9 +3788,7 @@ impl Clean for hir::ForeignItem { ForeignFunctionItem(Function { decl, generics, - unsafety: hir::Unsafety::Unsafe, - abi: Abi::Rust, - constness: hir::Constness::NotConst, + header: hir::FnHeader::default(), }) } hir::ForeignItemStatic(ref ty, mutbl) => { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index f85a70a6d401f..127949df2797c 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -13,7 +13,6 @@ pub use self::StructType::*; pub use self::TypeBound::*; -use rustc_target::spec::abi; use syntax::ast; use syntax::ast::{Name, NodeId}; use syntax::attr; @@ -149,11 +148,9 @@ pub struct Function { pub vis: hir::Visibility, pub stab: Option, pub depr: Option, - pub unsafety: hir::Unsafety, - pub constness: hir::Constness, + pub header: hir::FnHeader, pub whence: Span, pub generics: hir::Generics, - pub abi: abi::Abi, pub body: hir::BodyId, } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 109765b671197..4fb8a1b293e9e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -62,7 +62,6 @@ use rustc::middle::stability; use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; -use rustc_target::spec::abi; use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; use doctree; @@ -2423,7 +2422,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, let unsafety_flag = match myitem.inner { clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) - if func.unsafety == hir::Unsafety::Unsafe => { + if func.header.unsafety == hir::Unsafety::Unsafe => { "" } _ => "", @@ -2595,9 +2594,9 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, f: &clean::Function) -> fmt::Result { let name_len = format!("{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), - ConstnessSpace(f.constness), - UnsafetySpace(f.unsafety), - AbiSpace(f.abi), + ConstnessSpace(f.header.constness), + UnsafetySpace(f.header.unsafety), + AbiSpace(f.header.abi), it.name.as_ref().unwrap(), f.generics).len(); write!(w, "{}
", render_spotlight_traits(it)?)?;
@@ -2605,9 +2604,9 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     write!(w,
            "{vis}{constness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}
", vis = VisSpace(&it.visibility), - constness = ConstnessSpace(f.constness), - unsafety = UnsafetySpace(f.unsafety), - abi = AbiSpace(f.abi), + constness = ConstnessSpace(f.header.constness), + unsafety = UnsafetySpace(f.header.unsafety), + abi = AbiSpace(f.header.abi), name = it.name.as_ref().unwrap(), generics = f.generics, where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, @@ -3017,9 +3016,7 @@ fn render_assoc_item(w: &mut fmt::Formatter, parent: ItemType) -> fmt::Result { fn method(w: &mut fmt::Formatter, meth: &clean::Item, - unsafety: hir::Unsafety, - constness: hir::Constness, - abi: abi::Abi, + header: hir::FnHeader, g: &clean::Generics, d: &clean::FnDecl, link: AssocItemLink, @@ -3044,9 +3041,9 @@ fn render_assoc_item(w: &mut fmt::Formatter, }; let mut head_len = format!("{}{}{}{:#}fn {}{:#}", VisSpace(&meth.visibility), - ConstnessSpace(constness), - UnsafetySpace(unsafety), - AbiSpace(abi), + ConstnessSpace(header.constness), + UnsafetySpace(header.unsafety), + AbiSpace(header.abi), name, *g).len(); let (indent, end_newline) = if parent == ItemType::Trait { @@ -3058,9 +3055,9 @@ fn render_assoc_item(w: &mut fmt::Formatter, write!(w, "{}{}{}{}fn {name}\ {generics}{decl}{where_clause}", VisSpace(&meth.visibility), - ConstnessSpace(constness), - UnsafetySpace(unsafety), - AbiSpace(abi), + ConstnessSpace(header.constness), + UnsafetySpace(header.unsafety), + AbiSpace(header.abi), href = href, name = name, generics = *g, @@ -3078,12 +3075,10 @@ fn render_assoc_item(w: &mut fmt::Formatter, match item.inner { clean::StrippedItem(..) => Ok(()), clean::TyMethodItem(ref m) => { - method(w, item, m.unsafety, hir::Constness::NotConst, - m.abi, &m.generics, &m.decl, link, parent) + method(w, item, m.header, &m.generics, &m.decl, link, parent) } clean::MethodItem(ref m) => { - method(w, item, m.unsafety, m.constness, - m.abi, &m.generics, &m.decl, link, parent) + method(w, item, m.header, &m.generics, &m.decl, link, parent) } clean::AssociatedConstItem(ref ty, ref default) => { assoc_const(w, item, ty, default.as_ref(), link) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8c2555c4b3de2..02974ce5893bb 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -13,7 +13,6 @@ use std::mem; -use rustc_target::spec::abi; use syntax::ast; use syntax::attr; use syntax_pos::Span; @@ -172,9 +171,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { pub fn visit_fn(&mut self, item: &hir::Item, name: ast::Name, fd: &hir::FnDecl, - unsafety: &hir::Unsafety, - constness: hir::Constness, - abi: &abi::Abi, + header: hir::FnHeader, gen: &hir::Generics, body: hir::BodyId) -> Function { debug!("Visiting fn"); @@ -188,9 +185,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { name, whence: item.span, generics: gen.clone(), - unsafety: *unsafety, - constness, - abi: *abi, + header, body, } } @@ -458,9 +453,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { om.structs.push(self.visit_variant_data(item, name, sd, gen)), hir::ItemUnion(ref sd, ref gen) => om.unions.push(self.visit_union_data(item, name, sd, gen)), - hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) => - om.fns.push(self.visit_fn(item, name, &**fd, unsafety, - constness, abi, gen, body)), + hir::ItemFn(ref fd, header, ref gen, body) => + om.fns.push(self.visit_fn(item, name, &**fd, header, gen, body)), hir::ItemTy(ref ty, ref gen) => { let t = Typedef { ty: ty.clone(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c9843de547fb2..2b508e75a7210 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -18,7 +18,7 @@ pub use util::ThinVec; pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; -use codemap::{respan, Spanned}; +use codemap::{dummy_spanned, respan, Spanned}; use rustc_target::spec::abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; @@ -1364,9 +1364,7 @@ pub struct MutTy { /// or in an implementation. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { - pub unsafety: Unsafety, - pub constness: Spanned, - pub abi: Abi, + pub header: FnHeader, pub decl: P, } @@ -1747,6 +1745,12 @@ pub enum Unsafety { Normal, } +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum IsAsync { + Async, + NotAsync, +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Constness { Const, @@ -2045,6 +2049,29 @@ pub struct Item { pub tokens: Option, } +/// A function header +/// +/// All the information between the visibility & the name of the function is +/// included in this struct (e.g. `async unsafe fn` or `const extern "C" fn`) +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct FnHeader { + pub unsafety: Unsafety, + pub asyncness: IsAsync, + pub constness: Spanned, + pub abi: Abi, +} + +impl Default for FnHeader { + fn default() -> FnHeader { + FnHeader { + unsafety: Unsafety::Normal, + asyncness: IsAsync::NotAsync, + constness: dummy_spanned(Constness::NotConst), + abi: Abi::Rust, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ItemKind { /// An `extern crate` item, with optional *original* crate name if the crate was renamed. @@ -2066,7 +2093,7 @@ pub enum ItemKind { /// A function declaration (`fn` or `pub fn`). /// /// E.g. `fn foo(bar: usize) -> usize { .. }` - Fn(P, Unsafety, Spanned, Abi, Generics, P), + Fn(P, FnHeader, Generics, P), /// A module declaration (`mod` or `pub mod`). /// /// E.g. `mod foo;` or `mod foo { .. }` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 6664c0a5982ee..bee40a9a502cf 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1007,9 +1007,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { name, Vec::new(), ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)), - ast::Unsafety::Normal, - dummy_spanned(ast::Constness::NotConst), - Abi::Rust, + ast::FnHeader { + unsafety: ast::Unsafety::Normal, + asyncness: ast::IsAsync::NotAsync, + constness: dummy_spanned(ast::Constness::NotConst), + abi: Abi::Rust, + }, generics, body)) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3a02646d0af5f..ccf862a88b990 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -29,7 +29,6 @@ use rustc_target::spec::abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; use edition::{ALL_EDITIONS, Edition}; -use codemap::Spanned; use syntax_pos::{Span, DUMMY_SP}; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -473,6 +472,9 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), + + // Allows async and await syntax + (active, async_await, "1.27.0", Some(0), Some(Edition::Edition2018)), ); declare_features! ( @@ -1743,20 +1745,24 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn_decl: &'a ast::FnDecl, span: Span, _node_id: NodeId) { - // check for const fn declarations - if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) = - fn_kind { - gate_feature_post!(&self, const_fn, span, "const fn is unstable"); - } - // stability of const fn methods are covered in - // visit_trait_item and visit_impl_item below; this is - // because default methods don't pass through this - // point. - match fn_kind { - FnKind::ItemFn(_, _, _, abi, _, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => { - self.check_abi(abi, span); + FnKind::ItemFn(_, header, _, _) => { + // check for const fn and async fn declarations + if header.asyncness == ast::IsAsync::Async { + gate_feature_post!(&self, async_await, span, "async fn is unstable"); + } + if header.constness.node == ast::Constness::Const { + gate_feature_post!(&self, const_fn, span, "const fn is unstable"); + } + // stability of const fn methods are covered in + // visit_trait_item and visit_impl_item below; this is + // because default methods don't pass through this + // point. + + self.check_abi(header.abi, span); + } + FnKind::Method(_, sig, _, _) => { + self.check_abi(sig.header.abi, span); } _ => {} } @@ -1767,9 +1773,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match ti.node { ast::TraitItemKind::Method(ref sig, ref block) => { if block.is_none() { - self.check_abi(sig.abi, ti.span); + self.check_abi(sig.header.abi, ti.span); } - if sig.constness.node == ast::Constness::Const { + if sig.header.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } @@ -1803,7 +1809,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match ii.node { ast::ImplItemKind::Method(ref sig, _) => { - if sig.constness.node == ast::Constness::Const { + if sig.header.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1e5c6a6866bd9..29cd3c9380887 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -908,11 +908,11 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Const(t, e) => { ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e)) } - ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => { + ItemKind::Fn(decl, header, generics, body) => { let generics = folder.fold_generics(generics); let decl = folder.fold_fn_decl(decl); let body = folder.fold_block(body); - ItemKind::Fn(decl, unsafety, constness, abi, generics, body) + ItemKind::Fn(decl, header, generics, body) } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), @@ -1109,9 +1109,7 @@ pub fn noop_fold_foreign_item_simple(ni: ForeignItem, folder: &mut T) pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> MethodSig { MethodSig { - abi: sig.abi, - unsafety: sig.unsafety, - constness: sig.constness, + header: sig.header, decl: folder.fold_fn_decl(sig.decl) } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 25490829f9e56..1574abade1a46 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -934,12 +934,15 @@ mod tests { output: ast::FunctionRetTy::Default(sp(15, 15)), variadic: false }), - ast::Unsafety::Normal, - Spanned { - span: sp(0,2), - node: ast::Constness::NotConst, + ast::FnHeader { + unsafety: ast::Unsafety::Normal, + asyncness: ast::IsAsync::NotAsync, + constness: Spanned { + span: sp(0,2), + node: ast::Constness::NotConst, + }, + abi: Abi::Rust, }, - Abi::Rust, ast::Generics{ params: Vec::new(), where_clause: ast::WhereClause { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5a3e5586495cf..c91fd32b2d430 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -19,10 +19,10 @@ use ast::{Constness, Crate}; use ast::Defaultness; use ast::EnumDef; use ast::{Expr, ExprKind, RangeLimits}; -use ast::{Field, FnDecl}; +use ast::{Field, FnDecl, FnHeader}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::GenericParam; -use ast::{Ident, ImplItem, IsAuto, Item, ItemKind}; +use ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; use ast::{Label, Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; @@ -1422,10 +1422,13 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; let sig = ast::MethodSig { - unsafety, - constness, + header: FnHeader { + unsafety, + constness, + abi, + asyncness: IsAsync::NotAsync, + }, decl: d, - abi, }; let body = match self.token { @@ -5282,6 +5285,7 @@ impl<'a> Parser<'a> { /// Parse an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, + asyncness: IsAsync, constness: Spanned, abi: Abi) -> PResult<'a, ItemInfo> { @@ -5289,7 +5293,8 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_decl(false)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs))) + let header = FnHeader { unsafety, asyncness, constness, abi }; + Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) } /// true if we are looking at `const ID`, false for things like `const fn` etc @@ -5461,12 +5466,11 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig { - abi, - unsafety, - constness, - decl, - }, body))) + let header = ast::FnHeader { abi, unsafety, constness, asyncness: IsAsync::NotAsync }; + Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method( + ast::MethodSig { header, decl }, + body + ))) } } @@ -6527,6 +6531,7 @@ impl<'a> Parser<'a> { let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; @@ -6570,6 +6575,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, + IsAsync::NotAsync, respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; @@ -6597,6 +6603,31 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if self.eat_keyword(keywords::Async) { + // ASYNC FUNCTION ITEM + if self.check_keyword(keywords::Fn) + || (self.check_keyword(keywords::Unsafe) + && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { + let unsafety = self.parse_unsafety(); + self.bump(); + let fn_span = self.prev_span; + let (ident, item_, extra_attrs) = + self.parse_item_fn(unsafety, + IsAsync::Async, + respan(fn_span, Constness::NotConst), + Abi::Rust)?; + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } else { + // ERROR + panic!() + } + } if self.check_keyword(keywords::Unsafe) && (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) || self.look_ahead(1, |t| t.is_keyword(keywords::Auto))) @@ -6642,6 +6673,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; @@ -6667,6 +6699,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Unsafe, + IsAsync::NotAsync, respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 585d49d7076c4..87d846ae47258 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -373,14 +373,13 @@ pub fn vis_to_string(v: &ast::Visibility) -> String { } pub fn fun_to_string(decl: &ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, + header: ast::FnHeader, name: ast::Ident, generics: &ast::Generics) -> String { to_string(|s| { s.head("")?; - s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name), + s.print_fn(decl, header, Some(name), generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; s.end()?; // Close the head box s.end() // Close the outer box @@ -1112,9 +1111,8 @@ impl<'a> State<'a> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { self.head("")?; - self.print_fn(decl, ast::Unsafety::Normal, - ast::Constness::NotConst, - Abi::Rust, Some(item.ident), + self.print_fn(decl, ast::FnHeader::default(), + Some(item.ident), generics, &item.vis)?; self.end()?; // end head-ibox self.s.word(";")?; @@ -1243,13 +1241,11 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => { + ast::ItemKind::Fn(ref decl, header, ref typarams, ref body) => { self.head("")?; self.print_fn( decl, - unsafety, - constness.node, - abi, + header, Some(item.ident), typarams, &item.vis @@ -1576,9 +1572,7 @@ impl<'a> State<'a> { vis: &ast::Visibility) -> io::Result<()> { self.print_fn(&m.decl, - m.unsafety, - m.constness.node, - m.abi, + m.header, Some(ident), &generics, vis) @@ -2741,13 +2735,11 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &ast::FnDecl, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: abi::Abi, + header: ast::FnHeader, name: Option, generics: &ast::Generics, vis: &ast::Visibility) -> io::Result<()> { - self.print_fn_header_info(unsafety, constness, abi, vis)?; + self.print_fn_header_info(header, vis)?; if let Some(name) = name { self.nbsp()?; @@ -3064,9 +3056,7 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - unsafety, - ast::Constness::NotConst, - abi, + ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, name, &generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?; @@ -3129,22 +3119,25 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - unsafety: ast::Unsafety, - constness: ast::Constness, - abi: Abi, + header: ast::FnHeader, vis: &ast::Visibility) -> io::Result<()> { self.s.word(&visibility_qualified(vis, ""))?; - match constness { + match header.constness.node { ast::Constness::NotConst => {} ast::Constness::Const => self.word_nbsp("const")? } - self.print_unsafety(unsafety)?; + match header.asyncness { + ast::IsAsync::NotAsync => {} + ast::IsAsync::Async => self.word_nbsp("async")? + } + + self.print_unsafety(header.unsafety)?; - if abi != Abi::Rust { + if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string())?; + self.word_nbsp(&header.abi.to_string())?; } self.s.word("fn") diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 1dfd48a24c3bf..5a43211a627f3 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -124,9 +124,15 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { match i.node { - ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => { - let diag = self.cx.span_diagnostic; - diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise(); + ast::ItemKind::Fn(_, header, _, _) => { + if header.unsafety == ast::Unsafety::Unsafe { + let diag = self.cx.span_diagnostic; + diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise(); + } + if header.asyncness == ast::IsAsync::Async { + let diag = self.cx.span_diagnostic; + diag.span_fatal(i.span, "async functions cannot be used for tests").raise(); + } } _ => { debug!("this is a test function"); @@ -338,7 +344,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic"); match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + ast::ItemKind::Fn(ref decl, _, ref generics, _) => { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. let has_output = match decl.output { @@ -397,7 +403,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + ast::ItemKind::Fn(ref decl, _, ref generics, _) => { let input_cnt = decl.inputs.len(); // If the termination trait is active, the compiler will check that the output @@ -562,9 +568,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); let main_body = ecx.block(sp, vec![call_test_main]); let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)), - ast::Unsafety::Normal, - dummy_spanned(ast::Constness::NotConst), - ::rustc_target::spec::abi::Abi::Rust, + ast::FnHeader::default(), ast::Generics::default(), main_body); P(ast::Item { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index b6eb649daa24d..2ea2339163bb0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -23,17 +23,15 @@ //! instance, a walker looking for item names in a module will miss all of //! those that are created by the expansion of a macro. -use rustc_target::spec::abi::Abi; use ast::*; use syntax_pos::Span; -use codemap::Spanned; use parse::token::Token; use tokenstream::{TokenTree, TokenStream}; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, Unsafety, Spanned, Abi, &'a Visibility, &'a Block), + ItemFn(Ident, FnHeader, &'a Visibility, &'a Block), /// fn foo(&self) Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), @@ -227,10 +225,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_ty(typ); visitor.visit_expr(expr); } - ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { + ItemKind::Fn(ref declaration, header, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn(FnKind::ItemFn(item.ident, unsafety, - constness, abi, &item.vis, body), + visitor.visit_fn(FnKind::ItemFn(item.ident, header, + &item.vis, body), declaration, item.span, item.id) @@ -546,7 +544,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl where V: Visitor<'a>, { match kind { - FnKind::ItemFn(_, _, _, _, _, body) => { + FnKind::ItemFn(_, _, _, body) => { walk_fn_decl(visitor, declaration); visitor.visit_block(body); } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 80f65957c39a2..162e57702baf7 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -199,7 +199,7 @@ use syntax::ast::{ use syntax::attr; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; -use syntax::codemap::{self, dummy_spanned, respan}; +use syntax::codemap::{self, respan}; use syntax::util::move_map::MoveMap; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; @@ -986,10 +986,10 @@ impl<'a> MethodDef<'a> { defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { - abi, - unsafety, - constness: - dummy_spanned(ast::Constness::NotConst), + header: ast::FnHeader { + unsafety, abi, + ..ast::FnHeader::default() + }, decl: fn_decl, }, body_block), diff --git a/src/llvm b/src/llvm index 9ad4b7e8d7d16..1abfd0e562cc8 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 9ad4b7e8d7d1618fc9686aa8d3d0b4de3b7a6f36 +Subproject commit 1abfd0e562cc8f7a9577d97ee92246699093b954 diff --git a/src/tools/cargo b/src/tools/cargo index f352115d534eb..9e53ac6e6525d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit f352115d534ebdc8ec331209107f91a4f62da2e7 +Subproject commit 9e53ac6e6525da914cb05a85e5e8eff7b5dca81f diff --git a/src/tools/clippy b/src/tools/clippy index ebe0b0eed5962..c658fc8cbcd1f 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit ebe0b0eed596243a2839867363cb31d93f0b9754 +Subproject commit c658fc8cbcd1f199edd445a49cb43139ebdc5f02 diff --git a/src/tools/rls b/src/tools/rls index cf0609d0af0b7..3e3df0485004b 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit cf0609d0af0b734d4b9ee9dce6df66f946fc763f +Subproject commit 3e3df0485004bc1343bc8200b68c67ac7c479b28 diff --git a/src/tools/rustfmt b/src/tools/rustfmt index bf2581bf7709b..db8cb0b8d6942 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit bf2581bf7709b91c4431ba7074de910f72283e1f +Subproject commit db8cb0b8d6942d42a322b1d36b2504977404f362 From 8319f3db7bdbfccdf9eb62108a4c1af93196763b Mon Sep 17 00:00:00 2001 From: Without Boats Date: Thu, 17 May 2018 14:47:52 -0700 Subject: [PATCH 2/7] Display async fn in rustdoc. --- src/librustdoc/html/format.rs | 13 +++++++++++++ src/librustdoc/html/render.rs | 8 +++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 40dcd6e891fe8..fc397d0584009 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -39,6 +39,10 @@ pub struct UnsafetySpace(pub hir::Unsafety); /// with a space after it. #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); +/// Similarly to VisSpace, this structure is used to render a function asyncness +/// with a space after it. +#[derive(Copy, Clone)] +pub struct AsyncSpace(pub hir::IsAsync); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -962,6 +966,15 @@ impl fmt::Display for ConstnessSpace { } } +impl fmt::Display for AsyncSpace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + hir::IsAsync::Async => write!(f, "async "), + hir::IsAsync::NotAsync => Ok(()), + } + } +} + impl fmt::Display for clean::Import { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4fb8a1b293e9e..68345ab9857d6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -67,7 +67,7 @@ use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; use doctree; use fold::DocFolder; use html::escape::Escape; -use html::format::{ConstnessSpace}; +use html::format::{AsyncSpace, ConstnessSpace}; use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; @@ -2592,9 +2592,10 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, f: &clean::Function) -> fmt::Result { - let name_len = format!("{}{}{}{:#}fn {}{:#}", + let name_len = format!("{}{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), ConstnessSpace(f.header.constness), + AsyncSpace(f.header.asyncness), UnsafetySpace(f.header.unsafety), AbiSpace(f.header.abi), it.name.as_ref().unwrap(), @@ -2602,9 +2603,10 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "{}
", render_spotlight_traits(it)?)?;
     render_attributes(w, it)?;
     write!(w,
-           "{vis}{constness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}
", + "{vis}{constness}{asyncness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}", vis = VisSpace(&it.visibility), constness = ConstnessSpace(f.header.constness), + asyncness = AsyncSpace(f.header.asyncness), unsafety = UnsafetySpace(f.header.unsafety), abi = AbiSpace(f.header.abi), name = it.name.as_ref().unwrap(), From 1533923f04aff989a1a1115b4f055b10afffe100 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Wed, 23 May 2018 14:37:22 -0700 Subject: [PATCH 3/7] Lower the return type of async functions properly. --- src/librustc/hir/lowering.rs | 156 +++++++++++++++++++-- src/librustc_resolve/lib.rs | 4 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/build.rs | 2 + src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 11 +- src/libsyntax/ptr.rs | 10 ++ src/libsyntax/visit.rs | 8 +- 10 files changed, 174 insertions(+), 26 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a2eae6502ee37..20da2a6cae923 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -296,6 +296,14 @@ enum AnonymousLifetimeMode { PassThrough, } +trait FnRetTransform { + fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy; +} + +struct NonAsyncRet; +struct AsyncClosureRet; +struct AsyncFunctionRet; + impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { /// Full-crate AST visitor that inserts into a fresh @@ -1050,7 +1058,7 @@ impl<'a> LoweringContext<'a> { ), unsafety: this.lower_unsafety(f.unsafety), abi: f.abi, - decl: this.lower_fn_decl(&f.decl, None, false), + decl: this.lower_fn_decl(&f.decl, None, false, &NonAsyncRet), arg_names: this.lower_fn_args_to_names(&f.decl), })) }, @@ -1729,7 +1737,121 @@ impl<'a> LoweringContext<'a> { decl: &FnDecl, fn_def_id: Option, impl_trait_return_allow: bool, + fn_ret_transform: &FnRetTransform, ) -> P { + // For non async functions, the return type is lowered in a straightforward way + impl FnRetTransform for NonAsyncRet { + fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy { + match output { + FunctionRetTy::Ty(ty) => hir::Return(ctx.lower_ty(ty, impl_trait_context)), + FunctionRetTy::Default(span) => hir::DefaultReturn(*span), + } + } + } + + // For async closures: + // - If the return type is omitted, a straightforward lowering is performed + // - If the return type is explicit, given a return type T, it is lowered to + // ::std::raw::GenFuture<_, T> + impl FnRetTransform for AsyncClosureRet { + fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy { + match output { + FunctionRetTy::Ty(ty) => { + let inner_ty = ctx.lower_ty(ty, impl_trait_context); + let span = inner_ty.span; + let hir::Path { def, segments, .. } = ctx.std_path(span, &["raw", "GenFuture"], false); + let LoweredNodeId { node_id, hir_id } = ctx.next_id(); + let gen_future_path = hir::Path { + segments: segments.map_slice(|mut v| { + v.last_mut().unwrap().parameters = Some(P(hir::PathParameters { + lifetimes: hir_vec![], + bindings: hir_vec![], + types: hir_vec![ + P(hir::Ty { + id: node_id, + node: hir::TyInfer, + hir_id, span, + }), + inner_ty, + ], + parenthesized: false, + })); + v + }), + def, span + }; + + let LoweredNodeId { node_id, hir_id } = ctx.next_id(); + hir::Return(P(hir::Ty { + id: node_id, + node: hir::TyPath(hir::QPath::Resolved(None, P(gen_future_path))), + hir_id, span, + })) + } + FunctionRetTy::Default(span) => hir::DefaultReturn(*span), + } + } + } + + // For async functions the return type is lowered to impl ::std::future::Future + impl FnRetTransform for AsyncFunctionRet { + fn lower(&self, ctx: &mut LoweringContext, output: &FunctionRetTy, impl_trait_context: ImplTraitContext) -> hir::FunctionRetTy { + let inner_ty = match output { + FunctionRetTy::Ty(ty) => ctx.lower_ty(ty, impl_trait_context), + FunctionRetTy::Default(span) => { + let LoweredNodeId { node_id, hir_id } = ctx.next_id(); + P(hir::Ty { + id: node_id, + hir_id: hir_id, + node: hir::TyTup(hir_vec![]), + span: *span, + }) + } + }; + let span = inner_ty.span; + let hir::Path { def, segments, .. } = ctx.std_path(span, &["future", "Future"], false); + let future_path = hir::Path { + segments: segments.map_slice(|mut v| { + v.last_mut().unwrap().parameters = Some(P(hir::PathParameters { + lifetimes: hir_vec![], + types: hir_vec![], + bindings: hir_vec![hir::TypeBinding { + name: ctx.str_to_ident("Output"), + ty: inner_ty, + id: ctx.next_id().node_id, + span, + }], + parenthesized: false, + })); + v + }), + def, span + }; + let LoweredNodeId { hir_id, node_id } = ctx.next_id(); + hir::Return(P(hir::Ty { + id: node_id, + node: hir::TyImplTraitExistential(hir::ExistTy { + generics: hir::Generics::empty(), + bounds: hir_vec![hir::TyParamBound::TraitTyParamBound(hir::PolyTraitRef { + trait_ref: hir::TraitRef { + path: future_path, + ref_id: ctx.next_id().node_id, + }, + bound_generic_params: hir_vec![], + span, + }, hir::TraitBoundModifier::None)], + }, hir_vec![]), + hir_id, span, + })) + } + } + + let output_impl_trait_context = if fn_def_id.is_some() && impl_trait_return_allow { + ImplTraitContext::Existential + } else { + ImplTraitContext::Disallowed + }; + // NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some, // then impl Trait arguments are lowered into generic parameters on the given // fn_def_id, otherwise impl Trait is disallowed. (for now) @@ -1748,15 +1870,7 @@ impl<'a> LoweringContext<'a> { } }) .collect(), - output: match decl.output { - FunctionRetTy::Ty(ref ty) => match fn_def_id { - Some(_) if impl_trait_return_allow => { - hir::Return(self.lower_ty(ty, ImplTraitContext::Existential)) - } - _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), - }, - FunctionRetTy::Default(span) => hir::DefaultReturn(span), - }, + output: fn_ret_transform.lower(self, &decl.output, output_impl_trait_context), variadic: decl.variadic, has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node { TyKind::ImplicitSelf => true, @@ -2201,11 +2315,15 @@ impl<'a> LoweringContext<'a> { let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); + let fn_ret_transform: &FnRetTransform = match header.asyncness { + IsAsync::Async => &AsyncFunctionRet, + IsAsync::NotAsync => &NonAsyncRet, + }; let (generics, fn_decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, - |this| this.lower_fn_decl(decl, Some(fn_def_id), true), + |this| this.lower_fn_decl(decl, Some(fn_def_id), true, fn_ret_transform), ); hir::ItemFn( @@ -2721,7 +2839,7 @@ impl<'a> LoweringContext<'a> { |this| { ( // Disallow impl Trait in foreign items - this.lower_fn_decl(fdec, None, false), + this.lower_fn_decl(fdec, None, false, &NonAsyncRet), this.lower_fn_args_to_names(fdec), ) }, @@ -2747,9 +2865,13 @@ impl<'a> LoweringContext<'a> { fn_def_id: DefId, impl_trait_return_allow: bool, ) -> hir::MethodSig { + let fn_ret_transform: &FnRetTransform = match sig.header.asyncness { + IsAsync::Async => &AsyncFunctionRet, + IsAsync::NotAsync => &NonAsyncRet, + }; hir::MethodSig { header: self.lower_fn_header(sig.header), - decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow), + decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, fn_ret_transform), } } @@ -3074,7 +3196,7 @@ impl<'a> LoweringContext<'a> { arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal, ), - ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => { + ExprKind::Closure(capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) => { self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let mut is_generator = false; @@ -3108,9 +3230,13 @@ impl<'a> LoweringContext<'a> { } None }; + let fn_ret_transform: &FnRetTransform = match asyncness { + IsAsync::Async => &AsyncClosureRet, + IsAsync::NotAsync => &NonAsyncRet, + }; hir::ExprClosure( this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl, None, false), + this.lower_fn_decl(decl, None, false, fn_ret_transform), body_id, fn_decl_span, generator_option, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 84b17f155a0e9..4c4caf4309215 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -790,7 +790,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { FnKind::Method(_, _, _, _) => { TraitOrImplItemRibKind } - FnKind::Closure(_) => ClosureRibKind(node_id), + FnKind::Closure(..) => ClosureRibKind(node_id), }; // Create a value rib for the function. @@ -816,7 +816,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { FnKind::Method(.., body) => { self.visit_block(body); } - FnKind::Closure(body) => { + FnKind::Closure(_, body) => { self.visit_expr(body); } }; diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 279ee403cc625..3a8e2031ca663 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1549,7 +1549,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } } } - ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => { + ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => { let mut id = String::from("$"); id.push_str(&ex.id.to_string()); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2b508e75a7210..5d7b1f9d4f682 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1133,7 +1133,7 @@ pub enum ExprKind { /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, Movability, P, P, Span), + Closure(CaptureBy, IsAsync, Movability, P, P, Span), /// A block (`'label: { ... }`) Block(P, Option