From 9fed2d587c9d9f28003e23255b863897bd22a8b2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 04:21:16 +0100 Subject: [PATCH 01/11] parser: extract common foreign item code for each kind --- src/librustc_parse/parser/item.rs | 88 ++++++++----------------------- 1 file changed, 21 insertions(+), 67 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index ccd55c5c08a70..0a8f37708621a 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -740,7 +740,8 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; let defaultness = self.parse_defaultness(); - let (name, kind, generics) = if self.eat_keyword(kw::Type) { + + let (ident, kind, generics) = if self.eat_keyword(kw::Type) { self.parse_assoc_ty()? } else if self.check_fn_front_matter() { let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; @@ -751,17 +752,9 @@ impl<'a> Parser<'a> { self.parse_assoc_const()? }; - Ok(AssocItem { - id: DUMMY_NODE_ID, - span: lo.to(self.prev_span), - ident: name, - attrs, - vis, - defaultness, - generics, - kind, - tokens: None, - }) + let span = lo.to(self.prev_span); + let id = DUMMY_NODE_ID; + Ok(AssocItem { id, span, ident, attrs, vis, defaultness, generics, kind, tokens: None }) } /// This parses the grammar: @@ -967,7 +960,7 @@ impl<'a> Parser<'a> { Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } - /// Parses a foreign item. + /// Parses a foreign item (one in an `extern { ... }` block). pub fn parse_foreign_item(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtForeignItem, |ni| ni); @@ -975,27 +968,17 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; - if self.check_keyword(kw::Type) { + let (ident, kind) = if self.check_keyword(kw::Type) { // FOREIGN TYPE ITEM - self.parse_item_foreign_type(vis, lo, attrs) + self.parse_item_foreign_type()? } else if self.check_fn_front_matter() { // FOREIGN FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; - let kind = ForeignItemKind::Fn(sig, generics, body); - let span = lo.to(self.prev_span); - Ok(P(ast::ForeignItem { - ident, - attrs, - kind, - id: DUMMY_NODE_ID, - span, - vis, - tokens: None, - })) + (ident, ForeignItemKind::Fn(sig, generics, body)) } else if self.is_static_global() { // FOREIGN STATIC ITEM self.bump(); // `static` - self.parse_item_foreign_static(vis, lo, attrs) + self.parse_item_foreign_static()? } else if self.token.is_keyword(kw::Const) { // Treat `const` as `static` for error recovery, but don't add it to expected tokens. self.bump(); // `const` @@ -1007,66 +990,37 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); - self.parse_item_foreign_static(vis, lo, attrs) + self.parse_item_foreign_static()? } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? { - let kind = ForeignItemKind::Macro(mac); - let span = lo.to(self.prev_span); - let ident = Ident::invalid(); - Ok(P(ForeignItem { ident, span, id: DUMMY_NODE_ID, attrs, vis, kind, tokens: None })) + (Ident::invalid(), ForeignItemKind::Macro(mac)) } else { if !attrs.is_empty() { self.expected_item_err(&attrs)?; } - self.unexpected() - } + self.unexpected()? + }; + + let span = lo.to(self.prev_span); + Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) } /// Parses a static item from a foreign module. /// Assumes that the `static` keyword is already parsed. - fn parse_item_foreign_static( - &mut self, - vis: ast::Visibility, - lo: Span, - attrs: Vec, - ) -> PResult<'a, P> { + fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { let mutbl = self.parse_mutability(); let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let hi = self.token.span; self.expect_semi()?; - Ok(P(ForeignItem { - ident, - attrs, - kind: ForeignItemKind::Static(ty, mutbl), - id: DUMMY_NODE_ID, - span: lo.to(hi), - vis, - tokens: None, - })) + Ok((ident, ForeignItemKind::Static(ty, mutbl))) } /// Parses a type from a foreign module. - fn parse_item_foreign_type( - &mut self, - vis: ast::Visibility, - lo: Span, - attrs: Vec, - ) -> PResult<'a, P> { + fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> { self.expect_keyword(kw::Type)?; - let ident = self.parse_ident()?; - let hi = self.token.span; self.expect_semi()?; - Ok(P(ast::ForeignItem { - ident, - attrs, - kind: ForeignItemKind::Ty, - id: DUMMY_NODE_ID, - span: lo.to(hi), - vis, - tokens: None, - })) + Ok((ident, ForeignItemKind::Ty)) } fn is_static_global(&mut self) -> bool { From 7737d0ffdef6f3d7395e80291e3143522f46b95b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 06:43:33 +0100 Subject: [PATCH 02/11] parser: unify item list parsing. as a consequence, `trait X { #![attr] }` becomes legal. --- src/librustc_ast_pretty/pprust.rs | 1 + src/librustc_expand/expand.rs | 2 +- src/librustc_parse/parser/item.rs | 102 ++++++++---------- src/test/pretty/trait-inner-attr.rs | 7 ++ src/test/ui/parser/attrs-after-extern-mod.rs | 10 +- .../ui/parser/attrs-after-extern-mod.stderr | 2 +- .../ui/parser/doc-before-extern-rbrace.rs | 4 +- .../ui/parser/doc-before-extern-rbrace.stderr | 7 +- .../ui/parser/doc-inside-trait-item.stderr | 2 +- src/test/ui/parser/duplicate-visibility.rs | 3 + .../ui/parser/duplicate-visibility.stderr | 2 +- src/test/ui/parser/inner-attr-in-trait-def.rs | 9 ++ 12 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 src/test/pretty/trait-inner-attr.rs create mode 100644 src/test/ui/parser/inner-attr-in-trait-def.rs diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index b1fa818d0a8cf..75938470b6fca 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1269,6 +1269,7 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause); self.s.word(" "); self.bopen(); + self.print_inner_attributes(&item.attrs); for trait_item in trait_items { self.print_assoc_item(trait_item); } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 90692fe1ec9dd..0968e92c20314 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -867,7 +867,7 @@ pub fn parse_ast_fragment<'a>( AstFragmentKind::ForeignItems => { let mut items = SmallVec::new(); while this.token != token::Eof { - items.push(this.parse_foreign_item()?); + items.push(this.parse_foreign_item(&mut false)?); } AstFragment::ForeignItems(items) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 0a8f37708621a..f4ca84b005b84 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -515,7 +515,7 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; - let (impl_items, attrs) = self.parse_impl_body()?; + let (impl_items, attrs) = self.parse_item_list(|p, at_end| p.parse_impl_item(at_end))?; let item_kind = match ty_second { Some(ty_second) => { @@ -571,15 +571,21 @@ impl<'a> Parser<'a> { Ok((Ident::invalid(), item_kind, Some(attrs))) } - fn parse_impl_body(&mut self) -> PResult<'a, (Vec>, Vec)> { + fn parse_item_list( + &mut self, + mut parse_item: impl FnMut(&mut Parser<'a>, &mut bool) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, Vec)> { self.expect(&token::OpenDelim(token::Brace))?; let attrs = self.parse_inner_attributes()?; - let mut impl_items = Vec::new(); + let mut items = Vec::new(); while !self.eat(&token::CloseDelim(token::Brace)) { + if self.recover_doc_comment_before_brace() { + continue; + } let mut at_end = false; - match self.parse_impl_item(&mut at_end) { - Ok(impl_item) => impl_items.push(impl_item), + match parse_item(self, &mut at_end) { + Ok(item) => items.push(item), Err(mut err) => { err.emit(); if !at_end { @@ -589,7 +595,30 @@ impl<'a> Parser<'a> { } } } - Ok((impl_items, attrs)) + Ok((items, attrs)) + } + + /// Recover on a doc comment before `}`. + fn recover_doc_comment_before_brace(&mut self) -> bool { + if let token::DocComment(_) = self.token.kind { + if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) { + struct_span_err!( + self.diagnostic(), + self.token.span, + E0584, + "found a documentation comment that doesn't document anything", + ) + .span_label(self.token.span, "this doc comment doesn't document anything") + .help( + "doc comments must come before what they document, maybe a \ + comment was intended with `//`?", + ) + .emit(); + self.bump(); + return true; + } + } + false } /// Parses defaultness (i.e., `default` or nothing). @@ -660,39 +689,8 @@ impl<'a> Parser<'a> { } else { // It's a normal trait. tps.where_clause = self.parse_where_clause()?; - self.expect(&token::OpenDelim(token::Brace))?; - let mut trait_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - if let token::DocComment(_) = self.token.kind { - if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) { - struct_span_err!( - self.diagnostic(), - self.token.span, - E0584, - "found a documentation comment that doesn't document anything", - ) - .help( - "doc comments must come before what they document, maybe a \ - comment was intended with `//`?", - ) - .emit(); - self.bump(); - continue; - } - } - let mut at_end = false; - match self.parse_trait_item(&mut at_end) { - Ok(item) => trait_items.push(item), - Err(mut e) => { - e.emit(); - if !at_end { - self.consume_block(token::Brace, ConsumeClosingDelim::Yes); - break; - } - } - } - } - Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None)) + let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_trait_item(at_end))?; + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items), Some(attrs))) } } @@ -942,26 +940,18 @@ impl<'a> Parser<'a> { &mut self, lo: Span, abi: Option, - visibility: Visibility, + vis: Visibility, mut attrs: Vec, ) -> PResult<'a, P> { - self.expect(&token::OpenDelim(token::Brace))?; - - attrs.extend(self.parse_inner_attributes()?); - - let mut foreign_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - foreign_items.push(self.parse_foreign_item()?); - } - - let prev_span = self.prev_span; - let m = ast::ForeignMod { abi, items: foreign_items }; - let invalid = Ident::invalid(); - Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) + let (items, iattrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?; + attrs.extend(iattrs); + let span = lo.to(self.prev_span); + let m = ast::ForeignMod { abi, items }; + Ok(self.mk_item(span, Ident::invalid(), ItemKind::ForeignMod(m), vis, attrs)) } /// Parses a foreign item (one in an `extern { ... }` block). - pub fn parse_foreign_item(&mut self) -> PResult<'a, P> { + pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P> { maybe_whole!(self, NtForeignItem, |ni| ni); let mut attrs = self.parse_outer_attributes()?; @@ -973,7 +963,7 @@ impl<'a> Parser<'a> { self.parse_item_foreign_type()? } else if self.check_fn_front_matter() { // FOREIGN FUNCTION ITEM - let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; + let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, |_| true)?; (ident, ForeignItemKind::Fn(sig, generics, body)) } else if self.is_static_global() { // FOREIGN STATIC ITEM @@ -991,7 +981,7 @@ impl<'a> Parser<'a> { ) .emit(); self.parse_item_foreign_static()? - } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? { + } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), at_end)? { (Ident::invalid(), ForeignItemKind::Macro(mac)) } else { if !attrs.is_empty() { diff --git a/src/test/pretty/trait-inner-attr.rs b/src/test/pretty/trait-inner-attr.rs new file mode 100644 index 0000000000000..bb4fb1459bd64 --- /dev/null +++ b/src/test/pretty/trait-inner-attr.rs @@ -0,0 +1,7 @@ +// pp-exact + +trait Foo { + #![allow(bar)] +} + +fn main() { } diff --git a/src/test/ui/parser/attrs-after-extern-mod.rs b/src/test/ui/parser/attrs-after-extern-mod.rs index 4bdd16471cd80..ea899dca7b221 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.rs +++ b/src/test/ui/parser/attrs-after-extern-mod.rs @@ -1,13 +1,7 @@ -// Constants (static variables) can be used to match in patterns, but mutable -// statics cannot. This ensures that there's some form of error if this is -// attempted. +// Make sure there's an error when given `extern { ... #[attr] }`. -extern crate libc; +fn main() {} extern { - static mut rust_dbg_static_mut: libc::c_int; - pub fn rust_dbg_static_mut_check_four(); #[cfg(stage37)] //~ ERROR expected item after attributes } - -pub fn main() {} diff --git a/src/test/ui/parser/attrs-after-extern-mod.stderr b/src/test/ui/parser/attrs-after-extern-mod.stderr index cecdab4d63197..a02e738a2c38e 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.stderr +++ b/src/test/ui/parser/attrs-after-extern-mod.stderr @@ -1,5 +1,5 @@ error: expected item after attributes - --> $DIR/attrs-after-extern-mod.rs:10:19 + --> $DIR/attrs-after-extern-mod.rs:6:19 | LL | #[cfg(stage37)] | ^ diff --git a/src/test/ui/parser/doc-before-extern-rbrace.rs b/src/test/ui/parser/doc-before-extern-rbrace.rs index 695d4da1dca60..040206b80ffd0 100644 --- a/src/test/ui/parser/doc-before-extern-rbrace.rs +++ b/src/test/ui/parser/doc-before-extern-rbrace.rs @@ -1,4 +1,6 @@ +fn main() {} + extern { /// hi - //~^ ERROR expected item after doc comment + //~^ ERROR found a documentation comment that doesn't document anything } diff --git a/src/test/ui/parser/doc-before-extern-rbrace.stderr b/src/test/ui/parser/doc-before-extern-rbrace.stderr index 8cc9c916a7afd..0edceb268a7f5 100644 --- a/src/test/ui/parser/doc-before-extern-rbrace.stderr +++ b/src/test/ui/parser/doc-before-extern-rbrace.stderr @@ -1,8 +1,11 @@ -error: expected item after doc comment - --> $DIR/doc-before-extern-rbrace.rs:2:5 +error[E0584]: found a documentation comment that doesn't document anything + --> $DIR/doc-before-extern-rbrace.rs:4:5 | LL | /// hi | ^^^^^^ this doc comment doesn't document anything + | + = help: doc comments must come before what they document, maybe a comment was intended with `//`? error: aborting due to previous error +For more information about this error, try `rustc --explain E0584`. diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr index 261e27b6e0d18..246255a0a4675 100644 --- a/src/test/ui/parser/doc-inside-trait-item.stderr +++ b/src/test/ui/parser/doc-inside-trait-item.stderr @@ -2,7 +2,7 @@ error[E0584]: found a documentation comment that doesn't document anything --> $DIR/doc-inside-trait-item.rs:3:5 | LL | /// empty doc - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ this doc comment doesn't document anything | = help: doc comments must come before what they document, maybe a comment was intended with `//`? diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index a8f0b7d61b985..edbf508ecdb76 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -1,4 +1,7 @@ // error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn` + +fn main() {} + extern { pub pub fn foo(); } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index cba4058e48255..92cf348796943 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,5 +1,5 @@ error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub` - --> $DIR/duplicate-visibility.rs:3:9 + --> $DIR/duplicate-visibility.rs:6:9 | LL | pub pub fn foo(); | ^^^ expected one of 8 possible tokens diff --git a/src/test/ui/parser/inner-attr-in-trait-def.rs b/src/test/ui/parser/inner-attr-in-trait-def.rs new file mode 100644 index 0000000000000..8dba6b362cdfa --- /dev/null +++ b/src/test/ui/parser/inner-attr-in-trait-def.rs @@ -0,0 +1,9 @@ +// check-pass + +#![deny(non_camel_case_types)] + +fn main() {} + +trait foo_bar { + #![allow(non_camel_case_types)] +} From 511dfdb8b3d8c6d395b1b5a205c3464ae802509f Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 07:00:19 +0100 Subject: [PATCH 03/11] parser: extract `recover_missing_kw_before_item` --- src/librustc_parse/parser/item.rs | 174 +++++++++++++++--------------- 1 file changed, 90 insertions(+), 84 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index f4ca84b005b84..acbae7dfd6810 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -203,101 +203,107 @@ impl<'a> Parser<'a> { return Ok(Some(macro_def)); } - // Verify whether we have encountered a struct or method definition where the user forgot to - // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` if vis.node.is_pub() && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) { - // Space between `pub` keyword and the identifier - // - // pub S {} - // ^^^ `sp` points here - let sp = self.prev_span.between(self.token.span); - let full_sp = self.prev_span.to(self.token.span); - let ident_sp = self.token.span; - if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) { - // possible public struct definition where `struct` was forgotten - let ident = self.parse_ident().unwrap(); - let msg = format!("add `struct` here to parse `{}` as a public struct", ident); - let mut err = self.struct_span_err(sp, "missing `struct` for struct definition"); + self.recover_missing_kw_before_item()?; + } + self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis) + } + + /// Recover on encountering a struct or method definition where the user + /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`. + fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> { + // Space between `pub` keyword and the identifier + // + // pub S {} + // ^^^ `sp` points here + let sp = self.prev_span.between(self.token.span); + let full_sp = self.prev_span.to(self.token.span); + let ident_sp = self.token.span; + if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) { + // possible public struct definition where `struct` was forgotten + let ident = self.parse_ident().unwrap(); + let msg = format!("add `struct` here to parse `{}` as a public struct", ident); + let mut err = self.struct_span_err(sp, "missing `struct` for struct definition"); + err.span_suggestion_short( + sp, + &msg, + " struct ".into(), + Applicability::MaybeIncorrect, // speculative + ); + return Err(err); + } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { + let ident = self.parse_ident().unwrap(); + self.bump(); // `(` + let kw_name = self.recover_first_param(); + self.consume_block(token::Paren, ConsumeClosingDelim::Yes); + let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { + self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]); + self.bump(); // `{` + ("fn", kw_name, false) + } else if self.check(&token::OpenDelim(token::Brace)) { + self.bump(); // `{` + ("fn", kw_name, false) + } else if self.check(&token::Colon) { + let kw = "struct"; + (kw, kw, false) + } else { + ("fn` or `struct", "function or struct", true) + }; + + let msg = format!("missing `{}` for {} definition", kw, kw_name); + let mut err = self.struct_span_err(sp, &msg); + if !ambiguous { + self.consume_block(token::Brace, ConsumeClosingDelim::Yes); + let suggestion = + format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name); err.span_suggestion_short( sp, - &msg, - " struct ".into(), - Applicability::MaybeIncorrect, // speculative + &suggestion, + format!(" {} ", kw), + Applicability::MachineApplicable, ); - return Err(err); - } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { - let ident = self.parse_ident().unwrap(); - self.bump(); // `(` - let kw_name = self.recover_first_param(); - self.consume_block(token::Paren, ConsumeClosingDelim::Yes); - let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) { - self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]); - self.bump(); // `{` - ("fn", kw_name, false) - } else if self.check(&token::OpenDelim(token::Brace)) { - self.bump(); // `{` - ("fn", kw_name, false) - } else if self.check(&token::Colon) { - let kw = "struct"; - (kw, kw, false) - } else { - ("fn` or `struct", "function or struct", true) - }; - - let msg = format!("missing `{}` for {} definition", kw, kw_name); - let mut err = self.struct_span_err(sp, &msg); - if !ambiguous { - self.consume_block(token::Brace, ConsumeClosingDelim::Yes); - let suggestion = - format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name); - err.span_suggestion_short( - sp, - &suggestion, - format!(" {} ", kw), - Applicability::MachineApplicable, + } else { + if let Ok(snippet) = self.span_to_snippet(ident_sp) { + err.span_suggestion( + full_sp, + "if you meant to call a macro, try", + format!("{}!", snippet), + // this is the `ambiguous` conditional branch + Applicability::MaybeIncorrect, ); } else { - if let Ok(snippet) = self.span_to_snippet(ident_sp) { - err.span_suggestion( - full_sp, - "if you meant to call a macro, try", - format!("{}!", snippet), - // this is the `ambiguous` conditional branch - Applicability::MaybeIncorrect, - ); - } else { - err.help( - "if you meant to call a macro, remove the `pub` \ + err.help( + "if you meant to call a macro, remove the `pub` \ and add a trailing `!` after the identifier", - ); - } - } - return Err(err); - } else if self.look_ahead(1, |t| *t == token::Lt) { - let ident = self.parse_ident().unwrap(); - self.eat_to_tokens(&[&token::Gt]); - self.bump(); // `>` - let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { - ("fn", self.recover_first_param(), false) - } else if self.check(&token::OpenDelim(token::Brace)) { - ("struct", "struct", false) - } else { - ("fn` or `struct", "function or struct", true) - }; - let msg = format!("missing `{}` for {} definition", kw, kw_name); - let mut err = self.struct_span_err(sp, &msg); - if !ambiguous { - err.span_suggestion_short( - sp, - &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name), - format!(" {} ", kw), - Applicability::MachineApplicable, ); } - return Err(err); } + return Err(err); + } else if self.look_ahead(1, |t| *t == token::Lt) { + let ident = self.parse_ident().unwrap(); + self.eat_to_tokens(&[&token::Gt]); + self.bump(); // `>` + let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { + ("fn", self.recover_first_param(), false) + } else if self.check(&token::OpenDelim(token::Brace)) { + ("struct", "struct", false) + } else { + ("fn` or `struct", "function or struct", true) + }; + let msg = format!("missing `{}` for {} definition", kw, kw_name); + let mut err = self.struct_span_err(sp, &msg); + if !ambiguous { + err.span_suggestion_short( + sp, + &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name), + format!(" {} ", kw), + Applicability::MachineApplicable, + ); + } + return Err(err); + } else { + Ok(()) } - self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis) } pub(super) fn mk_item_with_info( From 73d5970cdc304c874cd6d7d594f3abb7317f1519 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 08:37:09 +0100 Subject: [PATCH 04/11] parser: introduce `parse_item_kind` as central `ItemInfo` logic. this also extracts macro item parsers. --- src/librustc_parse/parser/item.rs | 348 ++++++++---------- src/test/ui/pub/pub-restricted-error-fn.rs | 3 +- .../ui/pub/pub-restricted-error-fn.stderr | 14 +- 3 files changed, 168 insertions(+), 197 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index acbae7dfd6810..9ba3be041b5e6 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::BytePos; use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; -use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, StrLit, Unsafe}; +use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, Unsafe}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind}; @@ -83,45 +83,60 @@ impl<'a> Parser<'a> { }); let lo = self.token.span; - let vis = self.parse_visibility(FollowedByType::No)?; - if self.eat_keyword(kw::Use) { - // USE ITEM - let item_ = ItemKind::Use(P(self.parse_use_tree()?)); - self.expect_semi()?; + if let Some(info) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? { + return Ok(Some(self.mk_item_with_info(attrs, lo, vis, info))); + } - let span = lo.to(self.prev_span); - let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs); - return Ok(Some(item)); + // FAILURE TO PARSE ITEM + match vis.node { + VisibilityKind::Inherited => {} + _ => { + self.struct_span_err(vis.span, "unmatched visibility `pub`") + .span_label(vis.span, "the unmatched visibility") + .help("you likely meant to define an item, e.g., `pub fn foo() {}`") + .emit(); + } } - if self.check_fn_front_matter() { - // FUNCTION ITEM - let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?; - let kind = ItemKind::Fn(sig, generics, body); - return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)); + if !attributes_allowed && !attrs.is_empty() { + self.expected_item_err(&attrs)?; } + Ok(None) + } - if self.eat_keyword(kw::Extern) { + /// Parses one of the items allowed by the flags. + fn parse_item_kind( + &mut self, + attrs: &mut Vec, + macros_allowed: bool, + lo: Span, + vis: &Visibility, + ) -> PResult<'a, Option> { + let info = if self.eat_keyword(kw::Use) { + // USE ITEM + let tree = self.parse_use_tree()?; + self.expect_semi()?; + (Ident::invalid(), ItemKind::Use(P(tree)), None) + } else if self.check_fn_front_matter() { + // FUNCTION ITEM + let (ident, sig, generics, body) = self.parse_fn(&mut false, attrs, |_| true)?; + (ident, ItemKind::Fn(sig, generics, body), None) + } else if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { // EXTERN CRATE - return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); + self.parse_item_extern_crate()? + } else { + // EXTERN BLOCK + self.parse_item_foreign_mod()? } - // EXTERN BLOCK - let abi = self.parse_abi(); - return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?)); - } - - if self.is_static_global() { + } else if self.is_static_global() { // STATIC ITEM - self.bump(); + self.bump(); // `static` let m = self.parse_mutability(); - let info = self.parse_item_const(Some(m))?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if let Const::Yes(const_span) = self.parse_constness() { + self.parse_item_const(Some(m))? + } else if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM if self.eat_keyword(kw::Mut) { let prev_span = self.prev_span; @@ -136,18 +151,13 @@ impl<'a> Parser<'a> { .emit(); } - let info = self.parse_item_const(None)?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) { + self.parse_item_const(None)? + } else if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + { // UNSAFE TRAIT ITEM let unsafety = self.parse_unsafety(); - let info = self.parse_item_trait(lo, unsafety)?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.check_keyword(kw::Impl) + self.parse_item_trait(lo, unsafety)? + } else if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl]) || self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) { @@ -155,58 +165,48 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Impl)?; - let info = self.parse_item_impl(unsafety, defaultness)?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.eat_keyword(kw::Mod) { + self.parse_item_impl(unsafety, defaultness)? + } else if self.eat_keyword(kw::Mod) { // MODULE ITEM - let info = self.parse_item_mod(&attrs[..])?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.eat_keyword(kw::Type) { + self.parse_item_mod(&attrs[..])? + } else if self.eat_keyword(kw::Type) { // TYPE ITEM let (ident, ty, generics) = self.parse_type_alias()?; - let kind = ItemKind::TyAlias(ty, generics); - return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None)); - } - - if self.eat_keyword(kw::Enum) { + (ident, ItemKind::TyAlias(ty, generics), None) + } else if self.eat_keyword(kw::Enum) { // ENUM ITEM - let info = self.parse_item_enum()?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.check_keyword(kw::Trait) + self.parse_item_enum()? + } else if self.check_keyword(kw::Trait) || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])) { // TRAIT ITEM - let info = self.parse_item_trait(lo, Unsafe::No)?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.eat_keyword(kw::Struct) { + self.parse_item_trait(lo, Unsafe::No)? + } else if self.eat_keyword(kw::Struct) { // STRUCT ITEM - let info = self.parse_item_struct()?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if self.is_union_item() { + self.parse_item_struct()? + } else if self.is_union_item() { // UNION ITEM - self.bump(); - let info = self.parse_item_union()?; - return self.mk_item_with_info(attrs, lo, vis, info); - } - - if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? { - return Ok(Some(macro_def)); - } - - if vis.node.is_pub() && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) { + self.bump(); // `union` + self.parse_item_union()? + } else if self.eat_keyword(kw::Macro) { + // MACROS 2.0 ITEM + self.parse_item_decl_macro(lo)? + } else if self.is_macro_rules_item() { + // MACRO_RULES ITEM + self.parse_item_macro_rules(vis)? + } else if vis.node.is_pub() + && self.check_ident() + && self.look_ahead(1, |t| *t != token::Not) + { self.recover_missing_kw_before_item()?; - } - self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis) + return Ok(None); + } else if macros_allowed && self.token.is_path_start() { + // MACRO INVOCATION ITEM + self.parse_item_macro(vis)? + } else { + return Ok(None); + }; + Ok(Some(info)) } /// Recover on encountering a struct or method definition where the user @@ -312,11 +312,11 @@ impl<'a> Parser<'a> { lo: Span, vis: Visibility, info: ItemInfo, - ) -> PResult<'a, Option>> { + ) -> P { let (ident, item, extra_attrs) = info; let span = lo.to(self.prev_span); let attrs = Self::maybe_append(attrs, extra_attrs); - Ok(Some(self.mk_item(span, ident, item, vis, attrs))) + self.mk_item(span, ident, item, vis, attrs) } fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { @@ -326,49 +326,20 @@ impl<'a> Parser<'a> { lhs } - /// This is the fall-through for parsing items. - fn parse_macro_use_or_failure( - &mut self, - attrs: Vec, - macros_allowed: bool, - attributes_allowed: bool, - lo: Span, - visibility: Visibility, - ) -> PResult<'a, Option>> { - if macros_allowed - && self.token.is_path_start() - && !(self.is_async_fn() && self.token.span.rust_2015()) - { - // MACRO INVOCATION ITEM - - let prev_span = self.prev_span; - self.complain_if_pub_macro(&visibility.node, prev_span); - - // Item macro - let path = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; - let args = self.parse_mac_args()?; - if args.need_semicolon() && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - - let hi = self.prev_span; - let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription }; - let item = - self.mk_item(lo.to(hi), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs); - return Ok(Some(item)); - } + /// Parses an item macro, e.g., `item!();`. + fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { + self.complain_if_pub_macro(&vis.node, vis.span); - // FAILURE TO PARSE ITEM - match visibility.node { - VisibilityKind::Inherited => {} - _ => return Err(self.struct_span_err(self.prev_span, "unmatched visibility `pub`")), + // Item macro + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::Not)?; + let args = self.parse_mac_args()?; + if args.need_semicolon() && !self.eat(&token::Semi) { + self.report_invalid_macro_expansion_item(); } - if !attributes_allowed && !attrs.is_empty() { - self.expected_item_err(&attrs)?; - } - Ok(None) + let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription }; + Ok((Ident::invalid(), ItemKind::Mac(mac), None)) } /// Emits an expected-item-after-attributes error. @@ -874,12 +845,7 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; /// ``` - fn parse_item_extern_crate( - &mut self, - lo: Span, - visibility: Visibility, - attrs: Vec, - ) -> PResult<'a, P> { + fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemInfo> { // Accept `extern crate name-like-this` for better diagnostics let orig_name = self.parse_crate_name_with_dashes()?; let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? { @@ -888,9 +854,7 @@ impl<'a> Parser<'a> { (orig_name, None) }; self.expect_semi()?; - - let span = lo.to(self.prev_span); - Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs)) + Ok((item_name, ItemKind::ExternCrate(orig_name), None)) } fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { @@ -933,8 +897,7 @@ impl<'a> Parser<'a> { /// Parses `extern` for foreign ABIs modules. /// - /// `extern` is expected to have been - /// consumed before calling this method. + /// `extern` is expected to have been consumed before calling this method. /// /// # Examples /// @@ -942,18 +905,11 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} /// ``` - fn parse_item_foreign_mod( - &mut self, - lo: Span, - abi: Option, - vis: Visibility, - mut attrs: Vec, - ) -> PResult<'a, P> { - let (items, iattrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?; - attrs.extend(iattrs); - let span = lo.to(self.prev_span); - let m = ast::ForeignMod { abi, items }; - Ok(self.mk_item(span, Ident::invalid(), ItemKind::ForeignMod(m), vis, attrs)) + fn parse_item_foreign_mod(&mut self) -> PResult<'a, ItemInfo> { + let abi = self.parse_abi(); // ABI? + let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?; + let module = ast::ForeignMod { abi, items }; + Ok((Ident::invalid(), ItemKind::ForeignMod(module), Some(attrs))) } /// Parses a foreign item (one in an `extern { ... }` block). @@ -1386,64 +1342,72 @@ impl<'a> Parser<'a> { }) } - pub(super) fn eat_macro_def( - &mut self, - attrs: &[Attribute], - vis: &Visibility, - lo: Span, - ) -> PResult<'a, Option>> { - let (ident, def) = if self.eat_keyword(kw::Macro) { - let ident = self.parse_ident()?; + /// Parses a declarative macro 2.0 definition. + /// The `macro` keyword has already been parsed. + fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> { + let ident = self.parse_ident()?; + let body = if self.check(&token::OpenDelim(token::Brace)) { + self.parse_mac_args()? + } else if self.check(&token::OpenDelim(token::Paren)) { + let params = self.parse_token_tree(); + let pspan = params.span(); let body = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_mac_args()? - } else if self.check(&token::OpenDelim(token::Paren)) { - let params = self.parse_token_tree(); - let pspan = params.span(); - let body = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_token_tree() - } else { - return self.unexpected(); - }; - let bspan = body.span(); - let tokens = TokenStream::new(vec![ - params.into(), - TokenTree::token(token::FatArrow, pspan.between(bspan)).into(), - body.into(), - ]); - let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); - P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) + self.parse_token_tree() } else { return self.unexpected(); }; + let bspan = body.span(); + let tokens = TokenStream::new(vec![ + params.into(), + TokenTree::token(token::FatArrow, pspan.between(bspan)).into(), + body.into(), + ]); + let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); + P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) + } else { + return self.unexpected(); + }; + + self.sess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_span)); + Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: false }), None)) + } - (ident, ast::MacroDef { body, legacy: false }) - } else if self.check_keyword(sym::macro_rules) + /// Is this unambiguously the start of a `macro_rules! foo` item defnition? + fn is_macro_rules_item(&mut self) -> bool { + self.check_keyword(sym::macro_rules) && self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) - { - let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis.node, prev_span); - self.bump(); - self.bump(); - - let ident = self.parse_ident()?; - let body = self.parse_mac_args()?; - if body.need_semicolon() && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - - (ident, ast::MacroDef { body, legacy: true }) - } else { - return Ok(None); - }; + } - let span = lo.to(self.prev_span); + /// Parses a legacy `macro_rules! foo { ... }` declarative macro. + fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { + self.complain_if_pub_macro(&vis.node, vis.span); + self.expect_keyword(sym::macro_rules)?; // `macro_rules` + self.expect(&token::Not)?; // `!` - if !def.legacy { - self.sess.gated_spans.gate(sym::decl_macro, span); + let ident = self.parse_ident()?; + let body = self.parse_mac_args()?; + if body.need_semicolon() && !self.eat(&token::Semi) { + self.report_invalid_macro_expansion_item(); } - Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) + Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true }), None)) + } + + pub(super) fn eat_macro_def( + &mut self, + attrs: &[Attribute], + vis: &Visibility, + lo: Span, + ) -> PResult<'a, Option>> { + let info = if self.eat_keyword(kw::Macro) { + self.parse_item_decl_macro(lo)? + } else if self.is_macro_rules_item() { + self.parse_item_macro_rules(vis)? + } else { + return Ok(None); + }; + Ok(Some(self.mk_item_with_info(attrs.to_vec(), lo, vis.clone(), info))) } fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs index 56ee02f517c7b..3f8904fbe79d8 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.rs +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -1,3 +1,2 @@ -#![feature(pub_restricted)] - pub(crate) () fn foo() {} //~ unmatched visibility +//~^ ERROR expected item, found `(` diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr index fcff5334890eb..c5acb92dcd436 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.stderr +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -1,8 +1,16 @@ error: unmatched visibility `pub` - --> $DIR/pub-restricted-error-fn.rs:3:10 + --> $DIR/pub-restricted-error-fn.rs:1:1 | LL | pub(crate) () fn foo() {} - | ^ + | ^^^^^^^^^^ the unmatched visibility + | + = help: you likely meant to define an item, e.g., `pub fn foo() {}` + +error: expected item, found `(` + --> $DIR/pub-restricted-error-fn.rs:1:12 + | +LL | pub(crate) () fn foo() {} + | ^ expected item -error: aborting due to previous error +error: aborting due to 2 previous errors From 20ba6875e695dd985ba7f8974cc10c665f687670 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 11:35:36 +0100 Subject: [PATCH 05/11] parser_item_mod: avoid cloning outer attributes --- src/librustc_parse/config.rs | 11 +++-------- src/librustc_parse/parser/item.rs | 2 +- src/librustc_parse/parser/module.rs | 26 ++++++++++++-------------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 8dec64c579e88..1c479295af3ed 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -562,14 +562,9 @@ fn is_cfg(attr: &Attribute) -> bool { /// Process the potential `cfg` attributes on a module. /// Also determine if the module should be included in this configuration. -pub fn process_configure_mod( - sess: &ParseSess, - cfg_mods: bool, - attrs: &[Attribute], -) -> (bool, Vec) { +pub fn process_configure_mod(sess: &ParseSess, cfg_mods: bool, attrs: &mut Vec) -> bool { // Don't perform gated feature checking. let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - let mut attrs = attrs.to_owned(); - strip_unconfigured.process_cfg_attrs(&mut attrs); - (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs) + strip_unconfigured.process_cfg_attrs(attrs); + !cfg_mods || strip_unconfigured.in_cfg(&attrs) } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 9ba3be041b5e6..38e87cfbc07e7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -168,7 +168,7 @@ impl<'a> Parser<'a> { self.parse_item_impl(unsafety, defaultness)? } else if self.eat_keyword(kw::Mod) { // MODULE ITEM - self.parse_item_mod(&attrs[..])? + self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { // TYPE ITEM let (ident, ty, generics) = self.parse_type_alias()?; diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 0c8fad03d8690..36a1e87956fa6 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -40,36 +40,34 @@ impl<'a> Parser<'a> { } /// Parses a `mod { ... }` or `mod ;` item. - pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { - let (in_cfg, outer_attrs) = - crate::config::process_configure_mod(self.sess, self.cfg_mods, outer_attrs); + pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs); let id_span = self.token.span; let id = self.parse_ident()?; - if self.eat(&token::Semi) { + let (module, mut inner_attrs) = if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! let ModulePathSuccess { path, directory_ownership } = - self.submod_path(id, &outer_attrs, id_span)?; - let (module, attrs) = - self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?; - Ok((id, ItemKind::Mod(module), Some(attrs))) + self.submod_path(id, &attrs, id_span)?; + self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)? } else { - let placeholder = ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }; - Ok((id, ItemKind::Mod(placeholder), None)) + (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new()) } } else { let old_directory = self.directory.clone(); - self.push_directory(id, &outer_attrs); + self.push_directory(id, &attrs); self.expect(&token::OpenDelim(token::Brace))?; let mod_inner_lo = self.token.span; - let attrs = self.parse_inner_attributes()?; + let inner_attrs = self.parse_inner_attributes()?; let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; self.directory = old_directory; - Ok((id, ItemKind::Mod(module), Some(attrs))) - } + (module, inner_attrs) + }; + attrs.append(&mut inner_attrs); + Ok((id, ItemKind::Mod(module), None)) } /// Given a termination token, parses all of the items in a module. From c2026030b5d761a83d62c7e198057b119addcfd1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 12:09:21 +0100 Subject: [PATCH 06/11] parser: remove `Option>` in `ItemInfo`. --- src/librustc_parse/parser/item.rs | 107 +++++++++++++--------------- src/librustc_parse/parser/module.rs | 2 +- 2 files changed, 50 insertions(+), 59 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 38e87cfbc07e7..745d125b58c8f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -22,7 +22,7 @@ use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; use log::debug; use std::mem; -pub(super) type ItemInfo = (Ident, ItemKind, Option>); +pub(super) type ItemInfo = (Ident, ItemKind); impl<'a> Parser<'a> { pub fn parse_item(&mut self) -> PResult<'a, Option>> { @@ -85,8 +85,8 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; - if let Some(info) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? { - return Ok(Some(self.mk_item_with_info(attrs, lo, vis, info))); + if let Some((ident, kind)) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? { + return Ok(Some(self.mk_item(lo.to(self.prev_span), ident, kind, vis, attrs))); } // FAILURE TO PARSE ITEM @@ -118,18 +118,18 @@ impl<'a> Parser<'a> { // USE ITEM let tree = self.parse_use_tree()?; self.expect_semi()?; - (Ident::invalid(), ItemKind::Use(P(tree)), None) + (Ident::invalid(), ItemKind::Use(P(tree))) } else if self.check_fn_front_matter() { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(&mut false, attrs, |_| true)?; - (ident, ItemKind::Fn(sig, generics, body), None) + (ident, ItemKind::Fn(sig, generics, body)) } else if self.eat_keyword(kw::Extern) { if self.eat_keyword(kw::Crate) { // EXTERN CRATE self.parse_item_extern_crate()? } else { // EXTERN BLOCK - self.parse_item_foreign_mod()? + self.parse_item_foreign_mod(attrs)? } } else if self.is_static_global() { // STATIC ITEM @@ -156,7 +156,7 @@ impl<'a> Parser<'a> { { // UNSAFE TRAIT ITEM let unsafety = self.parse_unsafety(); - self.parse_item_trait(lo, unsafety)? + self.parse_item_trait(attrs, lo, unsafety)? } else if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl]) || self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) @@ -165,14 +165,14 @@ impl<'a> Parser<'a> { let defaultness = self.parse_defaultness(); let unsafety = self.parse_unsafety(); self.expect_keyword(kw::Impl)?; - self.parse_item_impl(unsafety, defaultness)? + self.parse_item_impl(attrs, unsafety, defaultness)? } else if self.eat_keyword(kw::Mod) { // MODULE ITEM self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { // TYPE ITEM let (ident, ty, generics) = self.parse_type_alias()?; - (ident, ItemKind::TyAlias(ty, generics), None) + (ident, ItemKind::TyAlias(ty, generics)) } else if self.eat_keyword(kw::Enum) { // ENUM ITEM self.parse_item_enum()? @@ -180,7 +180,7 @@ impl<'a> Parser<'a> { || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])) { // TRAIT ITEM - self.parse_item_trait(lo, Unsafe::No)? + self.parse_item_trait(attrs, lo, Unsafe::No)? } else if self.eat_keyword(kw::Struct) { // STRUCT ITEM self.parse_item_struct()? @@ -306,26 +306,6 @@ impl<'a> Parser<'a> { } } - pub(super) fn mk_item_with_info( - &self, - attrs: Vec, - lo: Span, - vis: Visibility, - info: ItemInfo, - ) -> P { - let (ident, item, extra_attrs) = info; - let span = lo.to(self.prev_span); - let attrs = Self::maybe_append(attrs, extra_attrs); - self.mk_item(span, ident, item, vis, attrs) - } - - fn maybe_append(mut lhs: Vec, mut rhs: Option>) -> Vec { - if let Some(ref mut rhs) = rhs { - lhs.append(rhs); - } - lhs - } - /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { self.complain_if_pub_macro(&vis.node, vis.span); @@ -339,7 +319,7 @@ impl<'a> Parser<'a> { } let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription }; - Ok((Ident::invalid(), ItemKind::Mac(mac), None)) + Ok((Ident::invalid(), ItemKind::Mac(mac))) } /// Emits an expected-item-after-attributes error. @@ -428,16 +408,21 @@ impl<'a> Parser<'a> { /// Parses an implementation item, `impl` keyword is already parsed. /// - /// impl<'a, T> TYPE { /* impl items */ } - /// impl<'a, T> TRAIT for TYPE { /* impl items */ } - /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } - /// impl<'a, T> const TRAIT for TYPE { /* impl items */ } + /// ``` + /// impl<'a, T> TYPE { /* impl items */ } + /// impl<'a, T> TRAIT for TYPE { /* impl items */ } + /// impl<'a, T> !TRAIT for TYPE { /* impl items */ } + /// impl<'a, T> const TRAIT for TYPE { /* impl items */ } + /// ``` /// /// We actually parse slightly more relaxed grammar for better error reporting and recovery. - /// `impl` GENERICS `const`? `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}` - /// `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}` + /// ``` + /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}" + /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}" + /// ``` fn parse_item_impl( &mut self, + attrs: &mut Vec, unsafety: Unsafe, defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { @@ -492,7 +477,7 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; - let (impl_items, attrs) = self.parse_item_list(|p, at_end| p.parse_impl_item(at_end))?; + let impl_items = self.parse_item_list(attrs, |p, at_end| p.parse_impl_item(at_end))?; let item_kind = match ty_second { Some(ty_second) => { @@ -545,15 +530,16 @@ impl<'a> Parser<'a> { } }; - Ok((Ident::invalid(), item_kind, Some(attrs))) + Ok((Ident::invalid(), item_kind)) } fn parse_item_list( &mut self, + attrs: &mut Vec, mut parse_item: impl FnMut(&mut Parser<'a>, &mut bool) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, Vec)> { + ) -> PResult<'a, Vec> { self.expect(&token::OpenDelim(token::Brace))?; - let attrs = self.parse_inner_attributes()?; + attrs.append(&mut self.parse_inner_attributes()?); let mut items = Vec::new(); while !self.eat(&token::CloseDelim(token::Brace)) { @@ -572,7 +558,7 @@ impl<'a> Parser<'a> { } } } - Ok((items, attrs)) + Ok(items) } /// Recover on a doc comment before `}`. @@ -624,7 +610,12 @@ impl<'a> Parser<'a> { } /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemInfo> { + fn parse_item_trait( + &mut self, + attrs: &mut Vec, + lo: Span, + unsafety: Unsafe, + ) -> PResult<'a, ItemInfo> { // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -662,12 +653,12 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::trait_alias, whole_span); - Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) + Ok((ident, ItemKind::TraitAlias(tps, bounds))) } else { // It's a normal trait. tps.where_clause = self.parse_where_clause()?; - let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_trait_item(at_end))?; - Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items), Some(attrs))) + let items = self.parse_item_list(attrs, |p, at_end| p.parse_trait_item(at_end))?; + Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items))) } } @@ -854,7 +845,7 @@ impl<'a> Parser<'a> { (orig_name, None) }; self.expect_semi()?; - Ok((item_name, ItemKind::ExternCrate(orig_name), None)) + Ok((item_name, ItemKind::ExternCrate(orig_name))) } fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { @@ -905,11 +896,11 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} /// ``` - fn parse_item_foreign_mod(&mut self) -> PResult<'a, ItemInfo> { + fn parse_item_foreign_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? - let (items, attrs) = self.parse_item_list(|p, at_end| p.parse_foreign_item(at_end))?; + let items = self.parse_item_list(attrs, |p, at_end| p.parse_foreign_item(at_end))?; let module = ast::ForeignMod { abi, items }; - Ok((Ident::invalid(), ItemKind::ForeignMod(module), Some(attrs))) + Ok((Ident::invalid(), ItemKind::ForeignMod(module))) } /// Parses a foreign item (one in an `extern { ... }` block). @@ -1016,7 +1007,7 @@ impl<'a> Parser<'a> { Some(m) => ItemKind::Static(ty, m, e), None => ItemKind::Const(ty, e), }; - Ok((id, item, None)) + Ok((id, item)) } /// We were supposed to parse `:` but instead, we're already at `=`. @@ -1069,7 +1060,7 @@ impl<'a> Parser<'a> { let enum_definition = EnumDef { variants: variants.into_iter().filter_map(|v| v).collect() }; - Ok((id, ItemKind::Enum(enum_definition, generics), None)) + Ok((id, ItemKind::Enum(enum_definition, generics))) } fn parse_enum_variant(&mut self) -> PResult<'a, Option> { @@ -1163,7 +1154,7 @@ impl<'a> Parser<'a> { return Err(err); }; - Ok((class_name, ItemKind::Struct(vdata, generics), None)) + Ok((class_name, ItemKind::Struct(vdata, generics))) } /// Parses `union Foo { ... }`. @@ -1187,7 +1178,7 @@ impl<'a> Parser<'a> { return Err(err); }; - Ok((class_name, ItemKind::Union(vdata, generics), None)) + Ok((class_name, ItemKind::Union(vdata, generics))) } pub(super) fn is_union_item(&self) -> bool { @@ -1369,7 +1360,7 @@ impl<'a> Parser<'a> { }; self.sess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_span)); - Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: false }), None)) + Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: false }))) } /// Is this unambiguously the start of a `macro_rules! foo` item defnition? @@ -1391,7 +1382,7 @@ impl<'a> Parser<'a> { self.report_invalid_macro_expansion_item(); } - Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true }), None)) + Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true }))) } pub(super) fn eat_macro_def( @@ -1400,14 +1391,14 @@ impl<'a> Parser<'a> { vis: &Visibility, lo: Span, ) -> PResult<'a, Option>> { - let info = if self.eat_keyword(kw::Macro) { + let (ident, kind) = if self.eat_keyword(kw::Macro) { self.parse_item_decl_macro(lo)? } else if self.is_macro_rules_item() { self.parse_item_macro_rules(vis)? } else { return Ok(None); }; - Ok(Some(self.mk_item_with_info(attrs.to_vec(), lo, vis.clone(), info))) + Ok(Some(self.mk_item(lo.to(self.prev_span), ident, kind, vis.clone(), attrs.to_vec()))) } fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs index 36a1e87956fa6..754923ae55e29 100644 --- a/src/librustc_parse/parser/module.rs +++ b/src/librustc_parse/parser/module.rs @@ -67,7 +67,7 @@ impl<'a> Parser<'a> { (module, inner_attrs) }; attrs.append(&mut inner_attrs); - Ok((id, ItemKind::Mod(module), None)) + Ok((id, ItemKind::Mod(module))) } /// Given a termination token, parses all of the items in a module. From fd64b3bcdfcc844b9b25318106917937f7b17b94 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 12:31:51 +0100 Subject: [PATCH 07/11] parser: make `eat_macro_def` redundant. --- src/librustc_parse/parser/item.rs | 35 ++++++++----------------------- src/librustc_parse/parser/stmt.rs | 10 +++------ 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 745d125b58c8f..27b3d501751b7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -86,7 +86,7 @@ impl<'a> Parser<'a> { let vis = self.parse_visibility(FollowedByType::No)?; if let Some((ident, kind)) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? { - return Ok(Some(self.mk_item(lo.to(self.prev_span), ident, kind, vis, attrs))); + return Ok(Some(P(self.mk_item(lo, ident, kind, vis, attrs)))); } // FAILURE TO PARSE ITEM @@ -942,9 +942,7 @@ impl<'a> Parser<'a> { } self.unexpected()? }; - - let span = lo.to(self.prev_span); - Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None })) + Ok(P(self.mk_item(lo, ident, kind, vis, attrs))) } /// Parses a static item from a foreign module. @@ -1364,7 +1362,7 @@ impl<'a> Parser<'a> { } /// Is this unambiguously the start of a `macro_rules! foo` item defnition? - fn is_macro_rules_item(&mut self) -> bool { + pub(super) fn is_macro_rules_item(&mut self) -> bool { self.check_keyword(sym::macro_rules) && self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) @@ -1385,22 +1383,6 @@ impl<'a> Parser<'a> { Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true }))) } - pub(super) fn eat_macro_def( - &mut self, - attrs: &[Attribute], - vis: &Visibility, - lo: Span, - ) -> PResult<'a, Option>> { - let (ident, kind) = if self.eat_keyword(kw::Macro) { - self.parse_item_decl_macro(lo)? - } else if self.is_macro_rules_item() { - self.parse_item_macro_rules(vis)? - } else { - return Ok(None); - }; - Ok(Some(self.mk_item(lo.to(self.prev_span), ident, kind, vis.clone(), attrs.to_vec()))) - } - fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { match *vis { VisibilityKind::Inherited => {} @@ -1496,15 +1478,16 @@ impl<'a> Parser<'a> { Ok(true) } - fn mk_item( + fn mk_item( &self, - span: Span, + lo: Span, ident: Ident, - kind: ItemKind, + kind: K, vis: Visibility, attrs: Vec, - ) -> P { - P(Item { ident, attrs, id: DUMMY_NODE_ID, kind, vis, span, tokens: None }) + ) -> Item { + let span = lo.to(self.prev_span); + Item { ident, attrs, id: DUMMY_NODE_ID, kind, vis, span, tokens: None } } } diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index e97af0dc00c69..b111b45e70990 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -7,10 +7,10 @@ use crate::maybe_whole; use crate::DirectoryOwnership; use rustc_errors::{Applicability, PResult}; -use rustc_span::source_map::{respan, BytePos, Span}; +use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Symbol}; use syntax::ast; -use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle, VisibilityKind}; +use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle}; use syntax::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; use syntax::ptr::P; use syntax::token::{self, TokenKind}; @@ -55,11 +55,6 @@ impl<'a> Parser<'a> { return self.recover_stmt_local(lo, attrs.into(), msg, "let"); } - let mac_vis = respan(lo, VisibilityKind::Inherited); - if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? { - return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def)))); - } - // Starts like a simple path, being careful to avoid contextual keywords // such as a union items, item with `crate` visibility or auto trait items. // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts @@ -70,6 +65,7 @@ impl<'a> Parser<'a> { && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path. && !self.is_auto_trait_item() && !self.is_async_fn() + && !self.is_macro_rules_item() { let path = self.parse_path(PathStyle::Expr)?; From 15e07a6a11bc5ed86e33403eb4b7d718d1636855 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 13:37:23 +0100 Subject: [PATCH 08/11] parser: fuse `trait` parsing & layer with `is_path_start_item` --- src/librustc_parse/parser/item.rs | 46 +++++++++++++++++-------------- src/librustc_parse/parser/stmt.rs | 16 +---------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 27b3d501751b7..6de82d8f9be59 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -152,11 +152,9 @@ impl<'a> Parser<'a> { } self.parse_item_const(None)? - } else if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) - { - // UNSAFE TRAIT ITEM - let unsafety = self.parse_unsafety(); - self.parse_item_trait(attrs, lo, unsafety)? + } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { + // TRAIT ITEM + self.parse_item_trait(attrs, lo)? } else if self.check_keyword(kw::Impl) || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl]) || self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe]) @@ -176,11 +174,6 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Enum) { // ENUM ITEM self.parse_item_enum()? - } else if self.check_keyword(kw::Trait) - || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])) - { - // TRAIT ITEM - self.parse_item_trait(attrs, lo, Unsafe::No)? } else if self.eat_keyword(kw::Struct) { // STRUCT ITEM self.parse_item_struct()? @@ -209,6 +202,15 @@ impl<'a> Parser<'a> { Ok(Some(info)) } + /// When parsing a statement, would the start of a path be an item? + pub(super) fn is_path_start_item(&mut self) -> bool { + self.is_crate_vis() // no: `crate::b`, yes: `crate $item` + || self.is_union_item() // no: `union::b`, yes: `union U { .. }` + || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` + || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac` + } + /// Recover on encountering a struct or method definition where the user /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`. fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> { @@ -338,7 +340,7 @@ impl<'a> Parser<'a> { Err(err) } - pub(super) fn is_async_fn(&self) -> bool { + fn is_async_fn(&self) -> bool { self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn]) } @@ -609,13 +611,17 @@ impl<'a> Parser<'a> { } } - /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`. - fn parse_item_trait( - &mut self, - attrs: &mut Vec, - lo: Span, - unsafety: Unsafe, - ) -> PResult<'a, ItemInfo> { + /// Is this an `(unsafe auto? | auto) trait` item? + fn check_auto_or_unsafe_trait_item(&mut self) -> bool { + // auto trait + self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait]) + // unsafe auto trait + || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + } + + /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. + fn parse_item_trait(&mut self, attrs: &mut Vec, lo: Span) -> PResult<'a, ItemInfo> { + let unsafety = self.parse_unsafety(); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No }; @@ -1179,7 +1185,7 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics))) } - pub(super) fn is_union_item(&self) -> bool { + fn is_union_item(&self) -> bool { self.token.is_keyword(kw::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } @@ -1362,7 +1368,7 @@ impl<'a> Parser<'a> { } /// Is this unambiguously the start of a `macro_rules! foo` item defnition? - pub(super) fn is_macro_rules_item(&mut self) -> bool { + fn is_macro_rules_item(&mut self) -> bool { self.check_keyword(sym::macro_rules) && self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index b111b45e70990..439d0368d0961 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -61,11 +61,7 @@ impl<'a> Parser<'a> { // like a path (1 token), but it fact not a path. if self.token.is_path_start() && !self.token.is_qpath_start() - && !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path. - && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path. - && !self.is_auto_trait_item() - && !self.is_async_fn() - && !self.is_macro_rules_item() + && !self.is_path_start_item() // Confirm we don't steal syntax from `parse_item_`. { let path = self.parse_path(PathStyle::Expr)?; @@ -295,16 +291,6 @@ impl<'a> Parser<'a> { } } - fn is_auto_trait_item(&self) -> bool { - // auto trait - (self.token.is_keyword(kw::Auto) && - self.is_keyword_ahead(1, &[kw::Trait])) - || // unsafe auto trait - (self.token.is_keyword(kw::Unsafe) && - self.is_keyword_ahead(1, &[kw::Auto]) && - self.is_keyword_ahead(2, &[kw::Trait])) - } - /// Parses a block. No inner attributes are allowed. pub fn parse_block(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtBlock, |x| x); From 46d3ef58a8a184b5a76098b2ac0e66792a6def25 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 31 Jan 2020 14:23:12 +0100 Subject: [PATCH 09/11] parser: extract `recover_const_mut`. --- src/librustc_parse/parser/item.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 6de82d8f9be59..f13898d702454 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -138,19 +138,7 @@ impl<'a> Parser<'a> { self.parse_item_const(Some(m))? } else if let Const::Yes(const_span) = self.parse_constness() { // CONST ITEM - if self.eat_keyword(kw::Mut) { - let prev_span = self.prev_span; - self.struct_span_err(prev_span, "const globals cannot be mutable") - .span_label(prev_span, "cannot be mutable") - .span_suggestion( - const_span, - "you might want to declare a static instead", - "static".to_owned(), - Applicability::MaybeIncorrect, - ) - .emit(); - } - + self.recover_const_mut(const_span); self.parse_item_const(None)? } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -987,6 +975,22 @@ impl<'a> Parser<'a> { } } + /// Recover on `const mut` with `const` already eaten. + fn recover_const_mut(&mut self, const_span: Span) { + if self.eat_keyword(kw::Mut) { + let span = self.prev_span; + self.struct_span_err(span, "const globals cannot be mutable") + .span_label(span, "cannot be mutable") + .span_suggestion( + const_span, + "you might want to declare a static instead", + "static".to_owned(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + } + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// From aaaf0ba072815d275820d8ac85ece6eeb9182321 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 1 Feb 2020 06:18:10 +0100 Subject: [PATCH 10/11] parser: misc small item related improvements & cleanups. --- src/librustc_parse/parser/item.rs | 258 ++++++++---------- src/librustc_parse/parser/mod.rs | 5 + src/librustc_parse/parser/stmt.rs | 18 +- src/test/ui/issues/issue-58856-2.stderr | 4 +- src/test/ui/issues/issue-60075.stderr | 2 +- src/test/ui/macros/issue-54441.rs | 3 +- src/test/ui/macros/issue-54441.stderr | 16 +- src/test/ui/parser/attr-before-eof.stderr | 4 +- .../ui/parser/attr-dangling-in-mod.stderr | 4 +- .../ui/parser/attrs-after-extern-mod.stderr | 4 +- src/test/ui/parser/default.rs | 3 +- src/test/ui/parser/default.stderr | 6 +- src/test/ui/parser/doc-before-attr.stderr | 6 +- src/test/ui/parser/duplicate-visibility.rs | 3 +- .../ui/parser/duplicate-visibility.stderr | 6 +- src/test/ui/parser/issue-19398.rs | 3 +- src/test/ui/parser/issue-19398.stderr | 13 +- src/test/ui/parser/issue-20711-2.rs | 3 +- src/test/ui/parser/issue-20711-2.stderr | 8 +- src/test/ui/parser/issue-20711.rs | 3 +- src/test/ui/parser/issue-20711.stderr | 8 +- src/test/ui/parser/issue-32446.stderr | 4 +- src/test/ui/parser/issue-41155.stderr | 4 +- ...-58094-missing-right-square-bracket.stderr | 4 +- src/test/ui/parser/macro/pub-item-macro.rs | 11 +- .../ui/parser/macro/pub-item-macro.stderr | 12 +- .../parser/macro/trait-non-item-macros.stderr | 4 +- .../missing-close-brace-in-impl-trait.rs | 6 +- .../missing-close-brace-in-impl-trait.stderr | 25 +- .../missing-close-brace-in-trait.rs | 2 +- .../missing-close-brace-in-trait.stderr | 6 +- src/test/ui/parser/pub-method-macro.rs | 3 +- src/test/ui/parser/pub-method-macro.stderr | 2 +- .../ui/parser/removed-syntax-static-fn.rs | 2 +- .../ui/parser/removed-syntax-static-fn.stderr | 13 +- .../ui/pub/pub-restricted-error-fn.stderr | 4 +- 36 files changed, 233 insertions(+), 249 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index f13898d702454..af9700ee81e55 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -8,8 +8,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey}; use rustc_span::source_map::{self, Span}; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::BytePos; -use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; +use syntax::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, Unsafe}; use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind}; @@ -90,18 +89,18 @@ impl<'a> Parser<'a> { } // FAILURE TO PARSE ITEM - match vis.node { - VisibilityKind::Inherited => {} - _ => { - self.struct_span_err(vis.span, "unmatched visibility `pub`") - .span_label(vis.span, "the unmatched visibility") - .help("you likely meant to define an item, e.g., `pub fn foo() {}`") - .emit(); - } + if let VisibilityKind::Inherited = vis.node { + } else { + let vs = pprust::vis_to_string(&vis); + let vs = vs.trim_end(); + self.struct_span_err(vis.span, &format!("unmatched visibility `{}`", vs)) + .span_label(vis.span, "the unmatched visibility") + .help(&format!("you likely meant to define an item, e.g., `{} fn foo() {{}}`", vs)) + .emit(); } - if !attributes_allowed && !attrs.is_empty() { - self.expected_item_err(&attrs)?; + if !attributes_allowed { + self.recover_attrs_no_item(&attrs)?; } Ok(None) } @@ -165,7 +164,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Struct) { // STRUCT ITEM self.parse_item_struct()? - } else if self.is_union_item() { + } else if self.is_kw_followed_by_ident(kw::Union) { // UNION ITEM self.bump(); // `union` self.parse_item_union()? @@ -175,15 +174,12 @@ impl<'a> Parser<'a> { } else if self.is_macro_rules_item() { // MACRO_RULES ITEM self.parse_item_macro_rules(vis)? - } else if vis.node.is_pub() - && self.check_ident() - && self.look_ahead(1, |t| *t != token::Not) - { + } else if vis.node.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); } else if macros_allowed && self.token.is_path_start() { // MACRO INVOCATION ITEM - self.parse_item_macro(vis)? + (Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?)) } else { return Ok(None); }; @@ -193,12 +189,17 @@ impl<'a> Parser<'a> { /// When parsing a statement, would the start of a path be an item? pub(super) fn is_path_start_item(&mut self) -> bool { self.is_crate_vis() // no: `crate::b`, yes: `crate $item` - || self.is_union_item() // no: `union::b`, yes: `union U { .. }` + || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac` } + /// Are we sure this could not possibly be a macro invocation? + fn isnt_macro_invocation(&mut self) -> bool { + self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep) + } + /// Recover on encountering a struct or method definition where the user /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`. fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> { @@ -297,33 +298,33 @@ impl<'a> Parser<'a> { } /// Parses an item macro, e.g., `item!();`. - fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { - self.complain_if_pub_macro(&vis.node, vis.span); - - // Item macro - let path = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; - let args = self.parse_mac_args()?; - if args.need_semicolon() && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } - - let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription }; - Ok((Ident::invalid(), ItemKind::Mac(mac))) - } - - /// Emits an expected-item-after-attributes error. - fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { - let message = match attrs.last() { - Some(&Attribute { kind: AttrKind::DocComment(_), .. }) => { - "expected item after doc comment" - } - _ => "expected item after attributes", + fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, Mac> { + let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` + self.expect(&token::Not)?; // `!` + let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. + self.eat_semi_for_macro_if_needed(&args); + self.complain_if_pub_macro(vis, false); + Ok(Mac { path, args, prior_type_ascription: self.last_type_ascription }) + } + + /// Recover if we parsed attributes and expected an item but there was none. + fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { + let (start, end) = match attrs { + [] => return Ok(()), + [x0] => (x0, x0), + [x0, .., xn] => (x0, xn), }; - - let mut err = self.struct_span_err(self.prev_span, message); - if attrs.last().unwrap().is_doc_comment() { - err.span_label(self.prev_span, "this doc comment doesn't document anything"); + let msg = if end.is_doc_comment() { + "expected item after doc comment" + } else { + "expected item after attributes" + }; + let mut err = self.struct_span_err(end.span, msg); + if end.is_doc_comment() { + err.span_label(end.span, "this doc comment doesn't document anything"); + } + if let [.., penultimate, _] = attrs { + err.span_label(start.span.to(penultimate.span), "other attributes here"); } Err(err) } @@ -332,38 +333,19 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn]) } - /// Parses a macro invocation inside a `trait`, `impl` or `extern` block. + /// Parses a macro invocation inside a `trait`, `impl`, or `extern` block. fn parse_assoc_macro_invoc( &mut self, item_kind: &str, - vis: Option<&Visibility>, + vis: &Visibility, at_end: &mut bool, ) -> PResult<'a, Option> { - if self.token.is_path_start() && !(self.is_async_fn() && self.token.span.rust_2015()) { - let prev_span = self.prev_span; - let path = self.parse_path(PathStyle::Mod)?; - - if path.segments.len() == 1 { - if !self.eat(&token::Not) { - return Err(self.missing_assoc_item_kind_err(item_kind, prev_span)); - } - } else { - self.expect(&token::Not)?; - } - - if let Some(vis) = vis { - self.complain_if_pub_macro(&vis.node, prev_span); - } - + if self.isnt_macro_invocation() { + Err(self.missing_assoc_item_kind_err(item_kind, self.prev_span)) + } else if self.token.is_path_start() { + let mac = self.parse_item_macro(vis)?; *at_end = true; - - // eat a matched-delimiter token tree: - let args = self.parse_mac_args()?; - if args.need_semicolon() { - self.expect_semi()?; - } - - Ok(Some(Mac { path, args, prior_type_ascription: self.last_type_ascription })) + Ok(Some(mac)) } else { Ok(None) } @@ -389,7 +371,7 @@ impl<'a> Parser<'a> { // | ^ missing `fn`, `type`, or `const` // pub path( // ^^ `sp` below will point to this - let sp = prev_span.between(self.prev_span); + let sp = prev_span.between(self.token.span); let mut err = self .struct_span_err(sp, &format!("{} for {}-item declaration", expected_kinds, item_type)); err.span_label(sp, expected_kinds); @@ -706,10 +688,13 @@ impl<'a> Parser<'a> { } else if self.check_fn_front_matter() { let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?; (ident, AssocItemKind::Fn(sig, body), generics) - } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? { + } else if self.check_keyword(kw::Const) { + self.parse_assoc_const()? + } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", &vis, at_end)? { (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) } else { - self.parse_assoc_const()? + self.recover_attrs_no_item(&attrs)?; + self.unexpected()? }; let span = lo.to(self.prev_span); @@ -813,7 +798,7 @@ impl<'a> Parser<'a> { fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { match self.token.kind { - token::Ident(name, false) if name == kw::Underscore => { + token::Ident(name @ kw::Underscore, false) => { let span = self.token.span; self.bump(); Ok(Ident::new(name, span)) @@ -928,12 +913,10 @@ impl<'a> Parser<'a> { ) .emit(); self.parse_item_foreign_static()? - } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), at_end)? { + } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", &vis, at_end)? { (Ident::invalid(), ForeignItemKind::Macro(mac)) } else { - if !attrs.is_empty() { - self.expected_item_err(&attrs)?; - } + self.recover_attrs_no_item(&attrs)?; self.unexpected()? }; Ok(P(self.mk_item(lo, ident, kind, vis, attrs))) @@ -1189,11 +1172,6 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics))) } - fn is_union_item(&self) -> bool { - self.token.is_keyword(kw::Union) - && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) - } - fn parse_record_struct_body( &mut self, ) -> PResult<'a, (Vec, /* recovered */ bool)> { @@ -1343,24 +1321,26 @@ impl<'a> Parser<'a> { /// Parses a declarative macro 2.0 definition. /// The `macro` keyword has already been parsed. + /// ``` + /// MacBody = "{" TOKEN_STREAM "}" ; + /// MacParams = "(" TOKEN_STREAM ")" ; + /// DeclMac = "macro" Ident MacParams? MacBody ; + /// ``` fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> { let ident = self.parse_ident()?; let body = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_mac_args()? + self.parse_mac_args()? // `MacBody` } else if self.check(&token::OpenDelim(token::Paren)) { - let params = self.parse_token_tree(); + let params = self.parse_token_tree(); // `MacParams` let pspan = params.span(); - let body = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_token_tree() - } else { + if !self.check(&token::OpenDelim(token::Brace)) { return self.unexpected(); - }; + } + let body = self.parse_token_tree(); // `MacBody` + // Convert `MacParams MacBody` into `{ MacParams => MacBody }`. let bspan = body.span(); - let tokens = TokenStream::new(vec![ - params.into(), - TokenTree::token(token::FatArrow, pspan.between(bspan)).into(), - body.into(), - ]); + let arrow = TokenTree::token(token::FatArrow, pspan.between(bspan)); // `=>` + let tokens = TokenStream::new(vec![params.into(), arrow.into(), body.into()]); let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi()); P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens)) } else { @@ -1380,65 +1360,68 @@ impl<'a> Parser<'a> { /// Parses a legacy `macro_rules! foo { ... }` declarative macro. fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> { - self.complain_if_pub_macro(&vis.node, vis.span); self.expect_keyword(sym::macro_rules)?; // `macro_rules` self.expect(&token::Not)?; // `!` let ident = self.parse_ident()?; let body = self.parse_mac_args()?; - if body.need_semicolon() && !self.eat(&token::Semi) { - self.report_invalid_macro_expansion_item(); - } + self.eat_semi_for_macro_if_needed(&body); + self.complain_if_pub_macro(vis, true); Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true }))) } - fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { - match *vis { - VisibilityKind::Inherited => {} - _ => { - let mut err = if self.token.is_keyword(sym::macro_rules) { - let mut err = - self.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); - err.span_suggestion( - sp, - "try exporting the macro", - "#[macro_export]".to_owned(), - Applicability::MaybeIncorrect, // speculative - ); - err - } else { - let mut err = - self.struct_span_err(sp, "can't qualify macro invocation with `pub`"); - err.help("try adjusting the macro to put `pub` inside the invocation"); - err - }; - err.emit(); - } + /// Item macro invocations or `macro_rules!` definitions need inherited visibility. + /// If that's not the case, emit an error. + fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) { + if let VisibilityKind::Inherited = vis.node { + return; + } + + let vstr = pprust::vis_to_string(vis); + let vstr = vstr.trim_end(); + if macro_rules { + let msg = format!("can't qualify macro_rules invocation with `{}`", vstr); + self.struct_span_err(vis.span, &msg) + .span_suggestion( + vis.span, + "try exporting the macro", + "#[macro_export]".to_owned(), + Applicability::MaybeIncorrect, // speculative + ) + .emit(); + } else { + self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`") + .span_suggestion( + vis.span, + "remove the visibility", + String::new(), + Applicability::MachineApplicable, + ) + .help(&format!("try adjusting the macro to put `{}` inside the invocation", vstr)) + .emit(); } } - fn report_invalid_macro_expansion_item(&self) { - let has_close_delim = self - .sess - .source_map() - .span_to_snippet(self.prev_span) - .map(|s| s.ends_with(")") || s.ends_with("]")) - .unwrap_or(false); + fn eat_semi_for_macro_if_needed(&mut self, args: &MacArgs) { + if args.need_semicolon() && !self.eat(&token::Semi) { + self.report_invalid_macro_expansion_item(args); + } + } + fn report_invalid_macro_expansion_item(&self, args: &MacArgs) { let mut err = self.struct_span_err( self.prev_span, "macros that expand to items must be delimited with braces or followed by a semicolon", ); - - // To avoid ICE, we shouldn't emit actual suggestions when it hasn't closing delims - if has_close_delim { + if self.unclosed_delims.is_empty() { + let DelimSpan { open, close } = match args { + MacArgs::Empty | MacArgs::Eq(..) => unreachable!(), + MacArgs::Delimited(dspan, ..) => *dspan, + }; err.multipart_suggestion( "change the delimiters to curly braces", - vec![ - (self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), '{'.to_string()), - (self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()), - ], + vec![(open, "{".to_string()), (close, '}'.to_string())], Applicability::MaybeIncorrect, ); } else { @@ -1449,14 +1432,13 @@ impl<'a> Parser<'a> { Applicability::HasPlaceholders, ); } - err.span_suggestion( self.prev_span.shrink_to_hi(), "add a semicolon", ';'.to_string(), Applicability::MaybeIncorrect, - ) - .emit(); + ); + err.emit(); } /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 4716d722778a6..79944dc35e523 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -572,6 +572,11 @@ impl<'a> Parser<'a> { if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) } } + /// Is the given keyword `kw` followed by a non-reserved identifier? + fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { + self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) + } + fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { if ok { true diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 439d0368d0961..742fc4802fd9d 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -8,7 +8,7 @@ use crate::DirectoryOwnership; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym}; use syntax::ast; use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle}; use syntax::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; @@ -55,13 +55,11 @@ impl<'a> Parser<'a> { return self.recover_stmt_local(lo, attrs.into(), msg, "let"); } - // Starts like a simple path, being careful to avoid contextual keywords - // such as a union items, item with `crate` visibility or auto trait items. - // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts - // like a path (1 token), but it fact not a path. - if self.token.is_path_start() - && !self.token.is_qpath_start() - && !self.is_path_start_item() // Confirm we don't steal syntax from `parse_item_`. + // Starts like a simple path, being careful to avoid contextual keywords, + // e.g., `union`, items with `crate` visibility, or `auto trait` items. + // We aim to parse an arbitrary path `a::b` but not something that starts like a path + // (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`. + if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item() { let path = self.parse_path(PathStyle::Expr)?; @@ -191,10 +189,6 @@ impl<'a> Parser<'a> { } } - fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { - self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) - } - fn recover_stmt_local( &mut self, lo: Span, diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr index 01d70d861e2c9..6221b90b31dd7 100644 --- a/src/test/ui/issues/issue-58856-2.stderr +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -7,11 +7,11 @@ LL | fn how_are_you(&self -> Empty { | | help: `)` may belong here | unclosed delimiter -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `)` --> $DIR/issue-58856-2.rs:11:1 | LL | } - | - expected one of 10 possible tokens + | - expected one of 11 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index 60eb99b46b79f..b2beb73503bb0 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` LL | }); | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `;` --> $DIR/issue-60075.rs:6:11 | LL | fn qux() -> Option { diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs index afdf76b7b580f..a70163df1cb93 100644 --- a/src/test/ui/macros/issue-54441.rs +++ b/src/test/ui/macros/issue-54441.rs @@ -1,6 +1,7 @@ macro_rules! m { + //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration () => { - let //~ ERROR expected + let }; } diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index c94355f47161c..761e7aec7235a 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,13 +1,11 @@ -error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let` - --> $DIR/issue-54441.rs:3:9 +error: missing `fn`, `type`, or `static` for extern-item declaration + --> $DIR/issue-54441.rs:1:1 | -LL | let - | ^^^ expected one of 9 possible tokens -... -LL | m!(); - | ----- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +LL | / macro_rules! m { +LL | | +LL | | () => { +LL | | let + | |________^ missing `fn`, `type`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/attr-before-eof.stderr b/src/test/ui/parser/attr-before-eof.stderr index eb5daf849811c..a2acb94372b8c 100644 --- a/src/test/ui/parser/attr-before-eof.stderr +++ b/src/test/ui/parser/attr-before-eof.stderr @@ -1,8 +1,8 @@ error: expected item after attributes - --> $DIR/attr-before-eof.rs:3:16 + --> $DIR/attr-before-eof.rs:3:1 | LL | #[derive(Debug)] - | ^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr-dangling-in-mod.stderr b/src/test/ui/parser/attr-dangling-in-mod.stderr index d896b61ce49c4..1c892eac08f3b 100644 --- a/src/test/ui/parser/attr-dangling-in-mod.stderr +++ b/src/test/ui/parser/attr-dangling-in-mod.stderr @@ -1,8 +1,8 @@ error: expected item after attributes - --> $DIR/attr-dangling-in-mod.rs:6:14 + --> $DIR/attr-dangling-in-mod.rs:6:1 | LL | #[foo = "bar"] - | ^ + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/attrs-after-extern-mod.stderr b/src/test/ui/parser/attrs-after-extern-mod.stderr index a02e738a2c38e..6060f3afe1e95 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.stderr +++ b/src/test/ui/parser/attrs-after-extern-mod.stderr @@ -1,8 +1,8 @@ error: expected item after attributes - --> $DIR/attrs-after-extern-mod.rs:6:19 + --> $DIR/attrs-after-extern-mod.rs:6:5 | LL | #[cfg(stage37)] - | ^ + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs index 17cd06864bf1d..65ecb1ebbe919 100644 --- a/src/test/ui/parser/default.rs +++ b/src/test/ui/parser/default.rs @@ -19,7 +19,8 @@ impl Foo for u16 { } impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo` - default pub fn foo() -> T { T::default() } //~ ERROR expected one of + default pub fn foo() -> T { T::default() } + //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration } fn main() {} diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index dde36cf8ddeed..ede9e47151863 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `pub` - --> $DIR/default.rs:22:13 +error: missing `fn`, `type`, or `const` for associated-item declaration + --> $DIR/default.rs:22:12 | LL | default pub fn foo() -> T { T::default() } - | ^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` + | ^ missing `fn`, `type`, or `const` error[E0449]: unnecessary visibility qualifier --> $DIR/default.rs:16:5 diff --git a/src/test/ui/parser/doc-before-attr.stderr b/src/test/ui/parser/doc-before-attr.stderr index 0fae44ce5c806..14fd01af2f98a 100644 --- a/src/test/ui/parser/doc-before-attr.stderr +++ b/src/test/ui/parser/doc-before-attr.stderr @@ -1,8 +1,10 @@ error: expected item after attributes - --> $DIR/doc-before-attr.rs:4:16 + --> $DIR/doc-before-attr.rs:4:1 | +LL | /// hi + | ------ other attributes here LL | #[derive(Debug)] - | ^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index edbf508ecdb76..1d271fa64b0ec 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -1,7 +1,6 @@ -// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn` - fn main() {} extern { pub pub fn foo(); + //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 92cf348796943..36a3a1ed5a0cc 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub` - --> $DIR/duplicate-visibility.rs:6:9 +error: missing `fn`, `type`, or `static` for extern-item declaration + --> $DIR/duplicate-visibility.rs:4:8 | LL | pub pub fn foo(); - | ^^^ expected one of 8 possible tokens + | ^ missing `fn`, `type`, or `static` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs index 2158a2fd6c11c..982a6be23ac5f 100644 --- a/src/test/ui/parser/issue-19398.rs +++ b/src/test/ui/parser/issue-19398.rs @@ -1,5 +1,6 @@ trait T { - extern "Rust" unsafe fn foo(); //~ ERROR expected one of `async`, `const` + //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration + extern "Rust" unsafe fn foo(); } fn main() {} diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index 201a6b2d66a7c..2bd6ac3a4b3a4 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,10 +1,11 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `extern` - --> $DIR/issue-19398.rs:2:5 +error: missing `fn`, `type`, or `const` for associated-item declaration + --> $DIR/issue-19398.rs:1:10 | -LL | trait T { - | - expected one of 10 possible tokens -LL | extern "Rust" unsafe fn foo(); - | ^^^^^^ unexpected token +LL | trait T { + | __________^ +LL | | +LL | | extern "Rust" unsafe fn foo(); + | |____^ missing `fn`, `type`, or `const` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711-2.rs b/src/test/ui/parser/issue-20711-2.rs index 0063a334182f4..168c7e76162bc 100644 --- a/src/test/ui/parser/issue-20711-2.rs +++ b/src/test/ui/parser/issue-20711-2.rs @@ -4,6 +4,7 @@ impl Foo { fn foo() {} #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or + //~^ ERROR expected item after attributes +} fn main() {} diff --git a/src/test/ui/parser/issue-20711-2.stderr b/src/test/ui/parser/issue-20711-2.stderr index ee484890fada8..10ef31584dec1 100644 --- a/src/test/ui/parser/issue-20711-2.stderr +++ b/src/test/ui/parser/issue-20711-2.stderr @@ -1,10 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}` - --> $DIR/issue-20711-2.rs:7:1 +error: expected item after attributes + --> $DIR/issue-20711-2.rs:6:5 | LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens -LL | } - | ^ unexpected token + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711.rs b/src/test/ui/parser/issue-20711.rs index dc216167b8a4f..020bb79d6e74e 100644 --- a/src/test/ui/parser/issue-20711.rs +++ b/src/test/ui/parser/issue-20711.rs @@ -2,6 +2,7 @@ struct Foo; impl Foo { #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or + //~^ ERROR expected item after attributes +} fn main() {} diff --git a/src/test/ui/parser/issue-20711.stderr b/src/test/ui/parser/issue-20711.stderr index 152c9f1c68975..66768de569418 100644 --- a/src/test/ui/parser/issue-20711.stderr +++ b/src/test/ui/parser/issue-20711.stderr @@ -1,10 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}` - --> $DIR/issue-20711.rs:5:1 +error: expected item after attributes + --> $DIR/issue-20711.rs:4:5 | LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens -LL | } - | ^ unexpected token + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index 1a97f54160b24..25c1efe35ae11 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `...` --> $DIR/issue-32446.rs:4:11 | LL | trait T { ... } - | ^^^ expected one of 10 possible tokens + | ^^^ expected one of 11 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr index 0e191eb7e0a04..327bc65818fa9 100644 --- a/src/test/ui/parser/issue-41155.stderr +++ b/src/test/ui/parser/issue-41155.stderr @@ -1,8 +1,8 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` +error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, `unsafe`, or identifier, found `}` --> $DIR/issue-41155.rs:5:1 | LL | pub - | - expected one of 8 possible tokens + | - expected one of 9 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr index 00f6652b311da..8a44ee761ed67 100644 --- a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr +++ b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr @@ -7,10 +7,10 @@ LL | #[Ѕ | unclosed delimiter error: expected item after attributes - --> $DIR/issue-58094-missing-right-square-bracket.rs:4:4 + --> $DIR/issue-58094-missing-right-square-bracket.rs:4:1 | LL | #[Ѕ - | ^ + | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/pub-item-macro.rs b/src/test/ui/parser/macro/pub-item-macro.rs index bae90227c62f4..f5f8a01e6a440 100644 --- a/src/test/ui/parser/macro/pub-item-macro.rs +++ b/src/test/ui/parser/macro/pub-item-macro.rs @@ -1,12 +1,15 @@ // Issue #14660 -macro_rules! priv_x { () => { - static x: u32 = 0; -}} +macro_rules! priv_x { + () => { + static x: u32 = 0; + }; +} macro_rules! pub_x { () => { pub priv_x!(); //~ ERROR can't qualify macro invocation with `pub` - //~^ HELP try adjusting the macro to put `pub` inside the invocation + //~^ HELP remove the visibility + //~| HELP try adjusting the macro to put `pub` inside the invocation }} mod foo { diff --git a/src/test/ui/parser/macro/pub-item-macro.stderr b/src/test/ui/parser/macro/pub-item-macro.stderr index 49644cf6a0e64..4ff96532e03a8 100644 --- a/src/test/ui/parser/macro/pub-item-macro.stderr +++ b/src/test/ui/parser/macro/pub-item-macro.stderr @@ -1,8 +1,8 @@ error: can't qualify macro invocation with `pub` - --> $DIR/pub-item-macro.rs:8:5 + --> $DIR/pub-item-macro.rs:10:5 | LL | pub priv_x!(); - | ^^^ + | ^^^ help: remove the visibility ... LL | pub_x!(); | --------- in this macro invocation @@ -11,16 +11,16 @@ LL | pub_x!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0603]: static `x` is private - --> $DIR/pub-item-macro.rs:17:23 + --> $DIR/pub-item-macro.rs:20:23 | LL | let y: u32 = foo::x; | ^ this static is private | note: the static `x` is defined here - --> $DIR/pub-item-macro.rs:4:5 + --> $DIR/pub-item-macro.rs:5:9 | -LL | static x: u32 = 0; - | ^^^^^^^^^^^^^^^^^^ +LL | static x: u32 = 0; + | ^^^^^^^^^^^^^^^^^^ ... LL | pub_x!(); | --------- in this macro invocation diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index 5a89b5b936f5b..9d05e85bcc00e 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2` +error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or identifier, found `2` --> $DIR/trait-non-item-macros.rs:2:19 | LL | ($a:expr) => ($a) - | ^^ expected one of 9 possible tokens + | ^^ expected one of 10 possible tokens ... LL | bah!(2); | -------- in this macro invocation diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs index 9f02a7a997bf2..592215030f552 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs @@ -1,12 +1,14 @@ +fn main() {} + impl T for () { //~ ERROR cannot find trait `T` in this scope fn foo(&self) {} +//~^ ERROR missing `fn`, `type`, or `const` -trait T { //~ ERROR expected one of +trait T { fn foo(&self); } pub(crate) struct Bar(); -fn main() {} //~ ERROR this file contains an unclosed delimiter diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr index a23cfeac58f84..1ec54525105f6 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/missing-close-brace-in-impl-trait.rs:12:52 + --> $DIR/missing-close-brace-in-impl-trait.rs:14:52 | LL | impl T for () { | - unclosed delimiter @@ -7,23 +7,18 @@ LL | impl T for () { LL | | ^ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `trait` - --> $DIR/missing-close-brace-in-impl-trait.rs:5:1 +error: missing `fn`, `type`, or `const` for associated-item declaration + --> $DIR/missing-close-brace-in-impl-trait.rs:5:17 | -LL | impl T for () { - | - unclosed delimiter -LL | -LL | fn foo(&self) {} - | - - | | - | expected one of 10 possible tokens - | help: `}` may belong here -LL | -LL | trait T { - | ^^^^^ unexpected token +LL | fn foo(&self) {} + | _________________^ +LL | | +LL | | +LL | | trait T { + | |_ missing `fn`, `type`, or `const` error[E0405]: cannot find trait `T` in this scope - --> $DIR/missing-close-brace-in-impl-trait.rs:1:6 + --> $DIR/missing-close-brace-in-impl-trait.rs:3:6 | LL | impl T for () { | ^ not found in this scope diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs index 5ec5d45bbe7b2..077e334719427 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs @@ -3,7 +3,7 @@ trait T { fn foo(&self); pub(crate) struct Bar(); -//~^ ERROR expected one of +//~^ ERROR missing `fn`, `type`, or `const` impl T for Bar { fn foo(&self) {} diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index 213640127829c..1bb153c461d90 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -7,11 +7,11 @@ LL | trait T { LL | fn main() {} | ^ -error: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct` - --> $DIR/missing-close-brace-in-trait.rs:5:12 +error: missing `fn`, `type`, or `const` for associated-item declaration + --> $DIR/missing-close-brace-in-trait.rs:5:11 | LL | pub(crate) struct Bar(); - | ^^^^^^ expected one of 7 possible tokens + | ^ missing `fn`, `type`, or `const` error[E0601]: `main` function not found in crate `missing_close_brace_in_trait` --> $DIR/missing-close-brace-in-trait.rs:1:1 diff --git a/src/test/ui/parser/pub-method-macro.rs b/src/test/ui/parser/pub-method-macro.rs index f04af1a0d65ff..0183bdcf6220b 100644 --- a/src/test/ui/parser/pub-method-macro.rs +++ b/src/test/ui/parser/pub-method-macro.rs @@ -15,7 +15,8 @@ mod bleh { impl S { pub defn!(f); //~ ERROR can't qualify macro invocation with `pub` - //~^ HELP try adjusting the macro to put `pub` inside the invocation + //~^ HELP remove the visibility + //~| HELP try adjusting the macro to put `pub` inside the invocation } } diff --git a/src/test/ui/parser/pub-method-macro.stderr b/src/test/ui/parser/pub-method-macro.stderr index 7b0fe4934610d..7c7a909267a1c 100644 --- a/src/test/ui/parser/pub-method-macro.stderr +++ b/src/test/ui/parser/pub-method-macro.stderr @@ -2,7 +2,7 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-method-macro.rs:17:9 | LL | pub defn!(f); - | ^^^ + | ^^^ help: remove the visibility | = help: try adjusting the macro to put `pub` inside the invocation diff --git a/src/test/ui/parser/removed-syntax-static-fn.rs b/src/test/ui/parser/removed-syntax-static-fn.rs index 0caddb9855d83..9e12222f3fd8b 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.rs +++ b/src/test/ui/parser/removed-syntax-static-fn.rs @@ -1,8 +1,8 @@ struct S; impl S { + //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration static fn f() {} - //~^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, } fn main() {} diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr index dfadefee23c15..5edf88026fbec 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.stderr +++ b/src/test/ui/parser/removed-syntax-static-fn.stderr @@ -1,10 +1,11 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `static` - --> $DIR/removed-syntax-static-fn.rs:4:5 +error: missing `fn`, `type`, or `const` for associated-item declaration + --> $DIR/removed-syntax-static-fn.rs:3:9 | -LL | impl S { - | - expected one of 10 possible tokens -LL | static fn f() {} - | ^^^^^^ unexpected token +LL | impl S { + | _________^ +LL | | +LL | | static fn f() {} + | |____^ missing `fn`, `type`, or `const` error: aborting due to previous error diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr index c5acb92dcd436..c0168b02da607 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.stderr +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -1,10 +1,10 @@ -error: unmatched visibility `pub` +error: unmatched visibility `pub(crate)` --> $DIR/pub-restricted-error-fn.rs:1:1 | LL | pub(crate) () fn foo() {} | ^^^^^^^^^^ the unmatched visibility | - = help: you likely meant to define an item, e.g., `pub fn foo() {}` + = help: you likely meant to define an item, e.g., `pub(crate) fn foo() {}` error: expected item, found `(` --> $DIR/pub-restricted-error-fn.rs:1:12 From ad72c3abb9a7f9746d6ccc381e69ba88fb15b5cd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 1 Feb 2020 10:26:11 +0100 Subject: [PATCH 11/11] parser: inline parse_assoc_macro_invoc --- src/librustc_parse/parser/item.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index af9700ee81e55..500aaaf43b92a 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -333,24 +333,6 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn]) } - /// Parses a macro invocation inside a `trait`, `impl`, or `extern` block. - fn parse_assoc_macro_invoc( - &mut self, - item_kind: &str, - vis: &Visibility, - at_end: &mut bool, - ) -> PResult<'a, Option> { - if self.isnt_macro_invocation() { - Err(self.missing_assoc_item_kind_err(item_kind, self.prev_span)) - } else if self.token.is_path_start() { - let mac = self.parse_item_macro(vis)?; - *at_end = true; - Ok(Some(mac)) - } else { - Ok(None) - } - } - fn missing_assoc_item_kind_err( &self, item_type: &str, @@ -690,7 +672,11 @@ impl<'a> Parser<'a> { (ident, AssocItemKind::Fn(sig, body), generics) } else if self.check_keyword(kw::Const) { self.parse_assoc_const()? - } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", &vis, at_end)? { + } else if self.isnt_macro_invocation() { + return Err(self.missing_assoc_item_kind_err("associated", self.prev_span)); + } else if self.token.is_path_start() { + let mac = self.parse_item_macro(&vis)?; + *at_end = true; (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default()) } else { self.recover_attrs_no_item(&attrs)?; @@ -913,7 +899,11 @@ impl<'a> Parser<'a> { ) .emit(); self.parse_item_foreign_static()? - } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", &vis, at_end)? { + } else if self.isnt_macro_invocation() { + return Err(self.missing_assoc_item_kind_err("extern", self.prev_span)); + } else if self.token.is_path_start() { + let mac = self.parse_item_macro(&vis)?; + *at_end = true; (Ident::invalid(), ForeignItemKind::Macro(mac)) } else { self.recover_attrs_no_item(&attrs)?;