Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deny async fn in 2015 edition #58678

Merged
merged 1 commit into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2906,7 +2906,7 @@ impl<'a> LoweringContext<'a> {
// `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, body);
let body_id = this.lower_async_body(decl, header.asyncness.node, body);

let (generics, fn_decl) = this.add_in_band_defs(
generics,
Expand All @@ -2916,7 +2916,7 @@ impl<'a> LoweringContext<'a> {
decl,
Some((fn_def_id, idty)),
true,
header.asyncness.opt_return_id()
header.asyncness.node.opt_return_id()
),
);

Expand Down Expand Up @@ -3410,14 +3410,14 @@ impl<'a> LoweringContext<'a> {
)
}
ImplItemKind::Method(ref sig, ref body) => {
let body_id = self.lower_async_body(&sig.decl, sig.header.asyncness, 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,
sig,
impl_item_def_id,
impl_trait_return_allow,
sig.header.asyncness.opt_return_id(),
sig.header.asyncness.node.opt_return_id(),
);
(generics, hir::ImplItemKind::Method(sig, body_id))
}
Expand Down Expand Up @@ -3637,7 +3637,7 @@ 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),
asyncness: self.lower_asyncness(h.asyncness.node),
constness: self.lower_constness(h.constness),
abi: h.abi,
}
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'a> DefCollector<'a> {
decl: &'a FnDecl,
body: &'a Block,
) {
let (closure_id, return_impl_trait_id) = match header.asyncness {
let (closure_id, return_impl_trait_id) = match header.asyncness.node {
IsAsync::Async {
closure_id,
return_impl_trait_id,
Expand Down Expand Up @@ -129,10 +129,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}
ItemKind::Fn(
ref decl,
ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
ref header,
ref generics,
ref body,
) => {
) if header.asyncness.node.is_async() => {
return self.visit_async_fn(
i.id,
i.ident.name,
Expand Down Expand Up @@ -242,9 +242,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
let def_data = match ii.node {
ImplItemKind::Method(MethodSig {
header: ref header @ FnHeader { asyncness: IsAsync::Async { .. }, .. },
ref header,
ref decl,
}, ref body) => {
}, ref body) if header.asyncness.node.is_async() => {
return self.visit_async_fn(
ii.id,
ii.ident.name,
Expand Down
14 changes: 11 additions & 3 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,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);
self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
}
}
}
Expand All @@ -482,9 +482,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.note("only trait implementations may be annotated with default").emit();
}
}
ItemKind::Fn(_, header, ref generics, _) => {
ItemKind::Fn(_, ref header, ref generics, _) => {
// We currently do not permit const generics in `const fn`, as
// this is tantamount to allowing compile-time dependent typing.
self.visit_fn_header(header);
if header.constness.node == Constness::Const {
// Look for const generics and error if we find any.
for param in &generics.params {
Expand Down Expand Up @@ -535,7 +536,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);
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| {
Expand Down Expand Up @@ -702,6 +703,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.span_bug(mac.span, "macro invocation missed in expansion; did you forget to override \
the relevant `fold_*()` method in `PlaceholderExpander`?");
}

fn visit_fn_header(&mut self, header: &'a FnHeader) {
if header.asyncness.node.is_async() && self.session.rust_2015() {
struct_span_err!(self.session, header.asyncness.span, E0670,
"`async fn` is not permitted in the 2015 edition").emit();
}
}
}

pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
Expand Down
12 changes: 12 additions & 0 deletions src/librustc_passes/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,18 @@ loop {
break;
}
```
"##,

E0670: r##"
Rust 2015 does not permit the use of `async fn`.

Example of erroneous code:

```compile_fail,E0670
async fn foo() {}
```

Switch to the Rust 2018 edition to use `async fn`.
"##
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,9 +806,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
debug!("(resolving function) entering function");
let (rib_kind, asyncness) = match function_kind {
FnKind::ItemFn(_, ref header, ..) =>
(ItemRibKind, header.asyncness),
(ItemRibKind, header.asyncness.node),
FnKind::Method(_, ref sig, _, _) =>
(TraitOrImplItemRibKind, sig.header.asyncness),
(TraitOrImplItemRibKind, sig.header.asyncness.node),
FnKind::Closure(_) =>
// Async closures aren't resolved through `visit_fn`-- they're
// processed separately
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_save_analysis/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ impl Sig for ast::Item {
if header.constness.node == ast::Constness::Const {
text.push_str("const ");
}
if header.asyncness.is_async() {
if header.asyncness.node.is_async() {
text.push_str("async ");
}
if header.unsafety == ast::Unsafety::Unsafe {
Expand Down Expand Up @@ -936,7 +936,7 @@ fn make_method_signature(
if m.header.constness.node == ast::Constness::Const {
text.push_str("const ");
}
if m.header.asyncness.is_async() {
if m.header.asyncness.node.is_async() {
text.push_str("async ");
}
if m.header.unsafety == ast::Unsafety::Unsafe {
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,7 @@ impl Item {
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub struct FnHeader {
pub unsafety: Unsafety,
pub asyncness: IsAsync,
pub asyncness: Spanned<IsAsync>,
pub constness: Spanned<Constness>,
pub abi: Abi,
}
Expand All @@ -2225,7 +2225,7 @@ impl Default for FnHeader {
fn default() -> FnHeader {
FnHeader {
unsafety: Unsafety::Normal,
asyncness: IsAsync::NotAsync,
asyncness: dummy_spanned(IsAsync::NotAsync),
constness: dummy_spanned(Constness::NotConst),
abi: Abi::Rust,
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)),
ast::FnHeader {
unsafety: ast::Unsafety::Normal,
asyncness: ast::IsAsync::NotAsync,
asyncness: dummy_spanned(ast::IsAsync::NotAsync),
constness: dummy_spanned(ast::Constness::NotConst),
abi: Abi::Rust,
},
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1894,7 +1894,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
match fn_kind {
FnKind::ItemFn(_, header, _, _) => {
// Check for const fn and async fn declarations.
if header.asyncness.is_async() {
if header.asyncness.node.is_async() {
gate_feature_post!(&self, async_await, span, "async fn is unstable");
}
// Stability of const fn methods are covered in
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ pub fn noop_flat_map_impl_item<T: MutVisitor>(mut item: ImplItem, visitor: &mut

pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
let FnHeader { unsafety: _, asyncness, constness: _, abi: _ } = header;
vis.visit_asyncness(asyncness);
vis.visit_asyncness(&mut asyncness.node);
}

pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
Expand Down
39 changes: 28 additions & 11 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5001,6 +5001,11 @@ impl<'a> Parser<'a> {
)
}

fn is_async_fn(&mut self) -> bool {
self.token.is_keyword(keywords::Async) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
}

fn is_do_catch_block(&mut self) -> bool {
self.token.is_keyword(keywords::Do) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
Expand Down Expand Up @@ -5133,7 +5138,8 @@ impl<'a> Parser<'a> {
!self.is_union_item() &&
!self.is_crate_vis() &&
!self.is_existential_type_decl() &&
!self.is_auto_trait_item() {
!self.is_auto_trait_item() &&
!self.is_async_fn() {
let pth = self.parse_path(PathStyle::Expr)?;

if !self.eat(&token::Not) {
Expand Down Expand Up @@ -6346,7 +6352,7 @@ impl<'a> Parser<'a> {
/// Parses an item-position function declaration.
fn parse_item_fn(&mut self,
unsafety: Unsafety,
asyncness: IsAsync,
asyncness: Spanned<IsAsync>,
constness: Spanned<Constness>,
abi: Abi)
-> PResult<'a, ItemInfo> {
Expand Down Expand Up @@ -6378,14 +6384,15 @@ impl<'a> Parser<'a> {
-> PResult<'a, (
Spanned<Constness>,
Unsafety,
IsAsync,
Spanned<IsAsync>,
Abi
)>
{
let is_const_fn = self.eat_keyword(keywords::Const);
let const_span = self.prev_span;
let unsafety = self.parse_unsafety();
let asyncness = self.parse_asyncness();
let asyncness = respan(self.prev_span, asyncness);
let (constness, unsafety, abi) = if is_const_fn {
(respan(const_span, Constness::Const), unsafety, Abi::Rust)
} else {
Expand Down Expand Up @@ -7796,7 +7803,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, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
abi)?;
let prev_span = self.prev_span;
Expand Down Expand Up @@ -7840,7 +7847,7 @@ impl<'a> Parser<'a> {
self.bump();
let (ident, item_, extra_attrs) =
self.parse_item_fn(unsafety,
IsAsync::NotAsync,
respan(const_span, IsAsync::NotAsync),
respan(const_span, Constness::Const),
Abi::Rust)?;
let prev_span = self.prev_span;
Expand Down Expand Up @@ -7888,14 +7895,15 @@ impl<'a> Parser<'a> {
// ASYNC FUNCTION ITEM
let unsafety = self.parse_unsafety();
self.expect_keyword(keywords::Async)?;
let async_span = self.prev_span;
self.expect_keyword(keywords::Fn)?;
let fn_span = self.prev_span;
let (ident, item_, extra_attrs) =
self.parse_item_fn(unsafety,
IsAsync::Async {
respan(async_span, IsAsync::Async {
closure_id: ast::DUMMY_NODE_ID,
return_impl_trait_id: ast::DUMMY_NODE_ID,
},
}),
respan(fn_span, Constness::NotConst),
Abi::Rust)?;
let prev_span = self.prev_span;
Expand All @@ -7904,6 +7912,13 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
if self.span.rust_2015() {
self.diagnostic().struct_span_err_with_code(
async_span,
"`async fn` is not permitted in the 2015 edition",
DiagnosticId::Error("E0670".into())
).emit();
}
return Ok(Some(item));
}
if self.check_keyword(keywords::Unsafe) &&
Expand Down Expand Up @@ -7951,7 +7966,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, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
Abi::Rust)?;
let prev_span = self.prev_span;
Expand All @@ -7977,7 +7992,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, IsAsync::NotAsync),
respan(fn_span, Constness::NotConst),
abi)?;
let prev_span = self.prev_span;
Expand Down Expand Up @@ -8244,7 +8259,8 @@ impl<'a> Parser<'a> {
lo: Span,
visibility: Visibility
) -> PResult<'a, Option<P<Item>>> {
if macros_allowed && self.token.is_path_start() {
if macros_allowed && self.token.is_path_start() &&
!(self.is_async_fn() && self.span.rust_2015()) {
// MACRO INVOCATION ITEM

let prev_span = self.prev_span;
Expand Down Expand Up @@ -8299,7 +8315,8 @@ impl<'a> Parser<'a> {
fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>,
at_end: &mut bool) -> PResult<'a, Option<Mac>>
{
if self.token.is_path_start() {
if self.token.is_path_start() &&
!(self.is_async_fn() && self.span.rust_2015()) {
let prev_span = self.prev_span;
let lo = self.span;
let pth = self.parse_path(PathStyle::Mod)?;
Expand Down
4 changes: 2 additions & 2 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3195,7 +3195,7 @@ impl<'a> State<'a> {
ast::Constness::Const => self.word_nbsp("const")?
}

self.print_asyncness(header.asyncness)?;
self.print_asyncness(header.asyncness.node)?;
self.print_unsafety(header.unsafety)?;

if header.abi != Abi::Rust {
Expand Down Expand Up @@ -3247,7 +3247,7 @@ mod tests {
ast::FnHeader {
unsafety: ast::Unsafety::Normal,
constness: source_map::dummy_spanned(ast::Constness::NotConst),
asyncness: ast::IsAsync::NotAsync,
asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync),
abi: Abi::Rust,
},
abba_ident,
Expand Down
Loading