From 1737d69c3b6632d56cd66144c9316ad643fb7507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Nov 2017 17:49:02 -0800 Subject: [PATCH 01/10] Fix underline in suggestions --- src/librustc_errors/emitter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 17ed1734fe203..108d8e687feae 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1155,7 +1155,7 @@ impl EmitterWriter { let start = parts[0].snippet.len() - parts[0].snippet.trim_left().len(); let sub_len = parts[0].snippet.trim().len(); let underline_start = span_start_pos.col.0 + start; - let underline_end = span_start_pos.col.0 + sub_len; + let underline_end = span_start_pos.col.0 + start + sub_len; for p in underline_start..underline_end { buffer.putc(row_num, max_line_num_len + 3 + p, From 547873aa54e787cbb7c266fb6e7337ea4e8a9331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 14 Nov 2017 17:49:29 -0800 Subject: [PATCH 02/10] Account for missing keyword in fn/struct definition --- src/libsyntax/parse/parser.rs | 53 ++++++++++++++++++- src/test/ui/suggestions/pub-ident-fn.rs | 15 ++++++ src/test/ui/suggestions/pub-ident-fn.stderr | 13 +++++ src/test/ui/suggestions/pub-ident-struct.rs | 13 +++++ .../ui/suggestions/pub-ident-struct.stderr | 13 +++++ 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/pub-ident-fn.rs create mode 100644 src/test/ui/suggestions/pub-ident-fn.stderr create mode 100644 src/test/ui/suggestions/pub-ident-struct.rs create mode 100644 src/test/ui/suggestions/pub-ident-struct.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0b03429ea2e52..fbc12872501c0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6236,7 +6236,58 @@ impl<'a> Parser<'a> { return Ok(Some(macro_def)); } - self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) + // Verify wether 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 visibility == Visibility::Public && self.check_ident() { + // Keep the current state of the parser to rollback after an unsuccessful attempt to + // parse an entire method or struct body. + let parser_snapshot = self.clone(); + + // Space between `pub` keyword and the identifier + // + // pub S {} + // ^^^ `sp` points here + let sp = self.prev_span.between(self.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(); + match self.parse_record_struct_body() { + Err(mut err) => { + // couldn't parse a struct body, continue parsing as if it were a macro + err.cancel(); + mem::replace(self, parser_snapshot); + } + Ok(_) => { + let msg = format!("add `struct` here to parse `{}` as a public struct", + ident); + let mut err = self.diagnostic() + .struct_span_err(sp, "missing `struct` for struct definition"); + err.span_suggestion_short(sp, &msg, " struct ".into()); + return Err(err); + } + } + } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { + // possible public method definition where `fn` was forgotten + let ident = self.parse_ident().unwrap(); + match self.parse_fn_decl(false) + .and_then(|_| self.parse_where_clause()) + .and_then(|_| self.parse_inner_attrs_and_block()) { + Err(mut err) => { + // couldn't parse method arguments or body, continue parsing + err.cancel(); + mem::replace(self, parser_snapshot); + } + Ok(_) => { + let msg = format!("add `fn` here to parse `{}` as a public method", ident); + let mut err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method definition"); + err.span_suggestion_short(sp, &msg, " fn ".into()); + return Err(err); + } + } + } + } + self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) } /// Parse a foreign item. diff --git a/src/test/ui/suggestions/pub-ident-fn.rs b/src/test/ui/suggestions/pub-ident-fn.rs new file mode 100644 index 0000000000000..043cf9328c920 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub foo(s: usize) -> bool { true } + +fn main() { + foo(2); +} diff --git a/src/test/ui/suggestions/pub-ident-fn.stderr b/src/test/ui/suggestions/pub-ident-fn.stderr new file mode 100644 index 0000000000000..19d3db157c239 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn.stderr @@ -0,0 +1,13 @@ +error: missing `fn` for method definition + --> $DIR/pub-ident-fn.rs:11:4 + | +11 | pub foo(s: usize) -> bool { true } + | ^^^ + | +help: add `fn` here to parse `foo` as a public method + | +11 | pub fn foo(s: usize) -> bool { true } + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/pub-ident-struct.rs b/src/test/ui/suggestions/pub-ident-struct.rs new file mode 100644 index 0000000000000..3e14a36dbab63 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-struct.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub S { +} +fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-struct.stderr b/src/test/ui/suggestions/pub-ident-struct.stderr new file mode 100644 index 0000000000000..bae2f6a4f809d --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-struct.stderr @@ -0,0 +1,13 @@ +error: missing `struct` for struct definition + --> $DIR/pub-ident-struct.rs:11:4 + | +11 | pub S { + | ^ + | +help: add `struct` here to parse `S` as a public struct + | +11 | pub struct S { + | ^^^^^^ + +error: aborting due to previous error + From 7c0387e36a1dab95492de61a2f26262a4526c286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 Nov 2017 06:49:15 -0800 Subject: [PATCH 03/10] Do not rewind parser and ignore following blocks When encountering `pub ident`, attempt to identify the code that comes afterwards, wether it is a brace block (assume it is a struct), a paren list followed by a colon (assume struct) or a paren list followed by a block (assume a fn). Consume those blocks to avoid any further parser errors and return a `Placeholder` item in order to allow the parser to continue. In the case of unenclosed blocks, the behavior is the same as it is currently: no further errors are processed. --- src/librustc/hir/lowering.rs | 4 +- src/librustc/hir/map/def_collector.rs | 1 + src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 3 +- src/librustc_save_analysis/sig.rs | 1 + src/libsyntax/ast.rs | 2 + src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 231 ++++++++++++++---- src/libsyntax/print/pprust.rs | 6 + src/libsyntax/visit.rs | 1 + .../pub-ident-missing-kw-unclosed-block.rs | 39 +++ ...pub-ident-missing-kw-unclosed-block.stderr | 36 +++ .../ui/suggestions/pub-ident-missing-kw.rs | 39 +++ .../suggestions/pub-ident-missing-kw.stderr | 69 ++++++ 14 files changed, 380 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs create mode 100644 src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr create mode 100644 src/test/ui/suggestions/pub-ident-missing-kw.rs create mode 100644 src/test/ui/suggestions/pub-ident-missing-kw.stderr diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3e527f43fec20..0fd2ae9dbc8aa 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1757,7 +1757,9 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), + ItemKind::Placeholder | ItemKind::MacroDef(..) | ItemKind::Mac(..) => { + panic!("Shouldn't still be around") + } } // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index d8590c1de94e9..c2dd7edbb1053 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -113,6 +113,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { return visit::walk_item(self, i); } ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), + ItemKind::Placeholder | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 46513a5740aed..1492c817ffd39 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -269,7 +269,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, imported_binding); } - ItemKind::GlobalAsm(..) => {} + ItemKind::GlobalAsm(..) | ItemKind::Placeholder => {} ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bd08d2c7989f..64d242307a7d8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1947,7 +1947,8 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) | + ItemKind::Placeholder => { // do nothing, these are just around to be encoded } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index b244876226c48..e7cf5782290ad 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -548,6 +548,7 @@ impl Sig for ast::Item { // FIXME should implement this (e.g., pub use). ast::ItemKind::Use(_) => Err("import"), ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"), + ast::ItemKind::Placeholder => Err("placeholder"), } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ad9d58651207d..a09cfbec879aa 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1977,6 +1977,7 @@ pub enum ItemKind { /// A macro definition. MacroDef(MacroDef), + Placeholder, } impl ItemKind { @@ -1998,6 +1999,7 @@ impl ItemKind { ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl(..) | + ItemKind::Placeholder | ItemKind::AutoImpl(..) => "item" } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index cc63bffec48a1..40370eb809688 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -935,6 +935,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)), + ItemKind::Placeholder => ItemKind::Placeholder, } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fbc12872501c0..0eda8e4d66b31 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -72,6 +72,50 @@ bitflags! { type ItemInfo = (Ident, ItemKind, Option >); +enum HasRecovered<'a, T> { + Success(T), + Recovered(T, DiagnosticBuilder<'a>), +} + +impl<'a, T> HasRecovered<'a, T> { + fn new(t: T, err: Option>) -> HasRecovered<'a, T> { + if let Some(err) = err { + HasRecovered::Recovered(t, err) + } else { + HasRecovered::Success(t) + } + } + + fn map O>(self, f: F) -> HasRecovered<'a, O> { + let (t, e) = self.full_unwrap(); + HasRecovered::new(f(t), e) + } + + fn emit(self) -> T { + match self { + HasRecovered::Recovered(t, mut err) => { + err.emit(); + t + } + HasRecovered::Success(t) => t, + } + } + + fn full_unwrap(self) -> (T, Option>) { + match self { + HasRecovered::Recovered(t, err) => (t, Some(err)), + HasRecovered::Success(t) => (t, None), + } + } + + fn into_result(self) -> PResult<'a, T> { + match self { + HasRecovered::Recovered(_, err) => Err(err), + HasRecovered::Success(t) => Ok(t), + } + } +} + /// How to parse a path. #[derive(Copy, Clone, PartialEq)] pub enum PathStyle { @@ -1156,6 +1200,7 @@ impl<'a> Parser<'a> { None => token::CloseDelim(self.token_cursor.frame.delim), }) } + fn look_ahead_span(&self, dist: usize) -> Span { if dist == 0 { return self.span @@ -1366,6 +1411,7 @@ impl<'a> Parser<'a> { debug!("parse_trait_methods(): parsing provided method"); *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let body = body.emit(); attrs.extend(inner_attrs.iter().cloned()); Some(body) } @@ -2401,7 +2447,7 @@ impl<'a> Parser<'a> { let mut attrs = outer_attrs; attrs.extend(self.parse_inner_attributes()?); - let blk = self.parse_block_tail(lo, blk_mode)?; + let blk = self.parse_block_tail(lo, blk_mode)?.emit(); return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } @@ -3157,7 +3203,9 @@ impl<'a> Parser<'a> { attrs.extend(iattrs); let hi = self.prev_span; - Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) + Ok(self.mk_expr(span_lo.to(hi), + ExprKind::ForLoop(pat, expr, loop_block.emit(), opt_ident), + attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) @@ -3169,6 +3217,7 @@ impl<'a> Parser<'a> { } let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; + let body = body.emit(); attrs.extend(iattrs); let span = span_lo.to(body.span); return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); @@ -3184,6 +3233,7 @@ impl<'a> Parser<'a> { let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); + let body = body.emit(); let span = span_lo.to(body.span); return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } @@ -3193,6 +3243,7 @@ impl<'a> Parser<'a> { span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; + let body = body.emit(); attrs.extend(iattrs); let span = span_lo.to(body.span); Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) @@ -3203,6 +3254,7 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; + let body = body.emit(); attrs.extend(iattrs); Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } @@ -4249,12 +4301,14 @@ impl<'a> Parser<'a> { return Err(e); } - self.parse_block_tail(lo, BlockCheckMode::Default) + Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?.emit()) } /// Parse a block. Inner attrs are allowed. - fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { - maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); + fn parse_inner_attrs_and_block(&mut self) + -> PResult<'a, (Vec, HasRecovered<'a, P>)> + { + maybe_whole!(self, NtBlock, |x| (Vec::new(), HasRecovered::Success(x))); let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; @@ -4264,11 +4318,22 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) + -> PResult<'a, HasRecovered<'a, P>> + { let mut stmts = vec![]; + let mut error = None; while !self.eat(&token::CloseDelim(token::Brace)) { - if let Some(stmt) = self.parse_full_stmt(false)? { + let stmt = match self.parse_full_stmt(false) { + Err(err) => { + error = Some(err); + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break); + break; + } + Ok(stmt) => stmt, + }; + if let Some(stmt) = stmt { stmts.push(stmt); } else if self.token == token::Eof { break; @@ -4277,13 +4342,14 @@ impl<'a> Parser<'a> { continue; }; } - - Ok(P(ast::Block { + let block = HasRecovered::new(P(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span), - })) + }), error); + + Ok(block) } /// Parse a statement, including the trailing semicolon. @@ -4918,11 +4984,22 @@ impl<'a> Parser<'a> { constness: Spanned, abi: abi::Abi) -> PResult<'a, ItemInfo> { + + self.parse_item_fn_recoverable(unsafety, constness, abi)?.into_result() + } + + fn parse_item_fn_recoverable(&mut self, + unsafety: Unsafety, + constness: Spanned, + abi: abi::Abi) + -> PResult<'a, HasRecovered<'a, ItemInfo>> { let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(false)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs))) + Ok(body.map(|body| (ident, + ItemKind::Fn(decl, unsafety, constness, abi, generics, body), + Some(inner_attrs)))) } /// true if we are looking at `const ID`, false for things like `const fn` etc @@ -5106,6 +5183,7 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; + let body = body.into_result()?; Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig { abi, unsafety, @@ -5325,18 +5403,54 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics), None)) } + fn consume_block(&mut self, delim: token::DelimToken) { + debug!("consuming {:?}", delim); + debug!("self.token {:?}", self.token); + let mut brace_depth = 0; + if !self.eat(&token::OpenDelim(delim)) { + debug!("didn't eat delim"); + return; + } + loop { + if self.eat(&token::OpenDelim(delim)) { + debug!("add depth"); + brace_depth += 1; + } else if self.eat(&token::CloseDelim(delim)) { + debug!("found closing"); + if brace_depth == 0 { + debug!("ending"); + return; + } else { + debug!("decrease"); + brace_depth -= 1; + continue; + } + } else if self.eat(&token::Eof) || self.eat(&token::CloseDelim(token::NoDelim)) { + debug!("eof or nodelim"); + return; + } else { + debug!("bump"); + self.bump(); + } + } + } + pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec> { let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { while self.token != token::CloseDelim(token::Brace) { - fields.push(self.parse_struct_decl_field().map_err(|e| { + let field = self.parse_struct_decl_field().map_err(|e| { self.recover_stmt(); - self.eat(&token::CloseDelim(token::Brace)); e - })?); + }); + match field { + Ok(field) => fields.push(field), + Err(mut err) => { + err.emit(); + } + } } - - self.bump(); + self.eat(&token::CloseDelim(token::Brace)); } else { let token_str = self.this_token_to_string(); return Err(self.fatal(&format!("expected `where`, or `{{` after struct \ @@ -6238,11 +6352,10 @@ impl<'a> Parser<'a> { // Verify wether 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 visibility == Visibility::Public && self.check_ident() { - // Keep the current state of the parser to rollback after an unsuccessful attempt to - // parse an entire method or struct body. - let parser_snapshot = self.clone(); - + if visibility == Visibility::Public && + self.check_ident() && + self.look_ahead(1, |t| *t != token::Not) + { // Space between `pub` keyword and the identifier // // pub S {} @@ -6251,40 +6364,54 @@ impl<'a> Parser<'a> { 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(); - match self.parse_record_struct_body() { - Err(mut err) => { - // couldn't parse a struct body, continue parsing as if it were a macro - err.cancel(); - mem::replace(self, parser_snapshot); - } - Ok(_) => { - let msg = format!("add `struct` here to parse `{}` as a public struct", - ident); - let mut err = self.diagnostic() - .struct_span_err(sp, "missing `struct` for struct definition"); - err.span_suggestion_short(sp, &msg, " struct ".into()); - return Err(err); - } - } + let msg = format!("add `struct` here to parse `{}` as a public struct", + ident); + let mut err = self.diagnostic() + .struct_span_err(sp, "missing `struct` for struct definition"); + err.span_suggestion_short(sp, &msg, " struct ".into()); + err.emit(); + self.consume_block(token::Brace); + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + ItemKind::Placeholder, + visibility, + vec![]); + return Ok(Some(item)); } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { - // possible public method definition where `fn` was forgotten let ident = self.parse_ident().unwrap(); - match self.parse_fn_decl(false) - .and_then(|_| self.parse_where_clause()) - .and_then(|_| self.parse_inner_attrs_and_block()) { - Err(mut err) => { - // couldn't parse method arguments or body, continue parsing - err.cancel(); - mem::replace(self, parser_snapshot); - } - Ok(_) => { - let msg = format!("add `fn` here to parse `{}` as a public method", ident); - let mut err = self.diagnostic() - .struct_span_err(sp, "missing `fn` for method definition"); - err.span_suggestion_short(sp, &msg, " fn ".into()); - return Err(err); - } + self.consume_block(token::Paren); + let (kw, ambiguous) = if self.check(&token::OpenDelim(token::Brace)) { + self.consume_block(token::Brace); + ("fn", false) + } else if self.check(&token::Colon) { + let kw = "struct"; + (kw, false) + } else { + ("fn` or `struct", true) + }; + + let msg = format!("missing `{}`{}", kw, + if ambiguous { + "".to_string() + } else { + format!(" for {} definition", kw) + }); + let mut err = self.diagnostic().struct_span_err(sp, &msg); + if !ambiguous { + let suggestion = format!("add `{kw}` here to parse `{}` as a public {kw}", + ident, + kw=kw); + err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw)); } + err.emit(); + let prev_span = self.prev_span; + let item = self.mk_item(lo.to(prev_span), + ident, + ItemKind::Placeholder, + visibility, + vec![]); + return Ok(Some(item)); } } self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 38627b40544f5..926bdd2a95776 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1386,6 +1386,12 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; } + ast::ItemKind::Placeholder => { + self.s.word("")?; + self.end()?; + } } self.ann.post(self, NodeItem(item)) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index c2e90f0bb13a3..5a6fbe0a8f89a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -307,6 +307,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), + ItemKind::Placeholder => (), } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs b/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs new file mode 100644 index 0000000000000..ceaaa0315d2e0 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs @@ -0,0 +1,39 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub Struct { + y: usize, +} + +pub Y { + x: usize, + + +pub struct X { + foo(); +} + +pub Z { + x->foo(), +} + +pub foo(foo) { + foo +} + +pub struct X { + foo(); +} + +pub Z { + x->foo(), +} + +fn main(){} diff --git a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr b/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr new file mode 100644 index 0000000000000..a580aaac8deba --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr @@ -0,0 +1,36 @@ +error: this file contains an un-closed delimiter + --> $DIR/pub-ident-missing-kw-unclosed-block.rs:29:13 + | +39 | fn main(){} + | ^ + | +help: did you mean to close this delimiter? + --> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:7 + | +15 | pub Y { + | ^ + +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw-unclosed-block.rs:1:4 + | +11 | pub Struct { + | ^ + | +help: add `struct` here to parse `Struct` as a public struct + | +11 | pub struct Struct { + | ^^^^^^ + +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:4 + | +15 | pub Y { + | ^ + | +help: add `struct` here to parse `Y` as a public struct + | +15 | pub struct Y { + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/suggestions/pub-ident-missing-kw.rs b/src/test/ui/suggestions/pub-ident-missing-kw.rs new file mode 100644 index 0000000000000..e2a7c394ec94b --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-missing-kw.rs @@ -0,0 +1,39 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub Struct { + y: usize, +} + +pub Y { + x: usize, +} + +pub struct X { + foo(); +} + +pub Z { + x->foo(), +} + +pub foo(foo) { + foo +} + +pub struct X { + foo(); +} + +pub Z { + x->foo(), +} + +fn main(){} diff --git a/src/test/ui/suggestions/pub-ident-missing-kw.stderr b/src/test/ui/suggestions/pub-ident-missing-kw.stderr new file mode 100644 index 0000000000000..23ac4eca2b42f --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-missing-kw.stderr @@ -0,0 +1,69 @@ +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw.rs:11:4 + | +11 | pub Struct { + | ^ + | +help: add `struct` here to parse `Struct` as a public struct + | +11 | pub struct Struct { + | ^^^^^^ + +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw.rs:15:4 + | +15 | pub Y { + | ^ + | +help: add `struct` here to parse `Y` as a public struct + | +15 | pub struct Y { + | ^^^^^^ + +error: expected `:`, found `(` + --> $DIR/pub-ident-missing-kw.rs:20:8 + | +20 | foo(); + | ^ + +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw.rs:23:4 + | +23 | pub Z { + | ^ + | +help: add `struct` here to parse `Z` as a public struct + | +23 | pub struct Z { + | ^^^^^^ + +error: missing `fn` for fn definition + --> $DIR/pub-ident-missing-kw.rs:27:4 + | +27 | pub foo(foo) { + | ^ + | +help: add `fn` here to parse `foo` as a public fn + | +27 | pub fn foo(foo) { + | ^^ + +error: expected `:`, found `(` + --> $DIR/pub-ident-missing-kw.rs:32:8 + | +32 | foo(); + | ^ + +error: missing `struct` for struct definition + --> $DIR/pub-ident-missing-kw.rs:35:4 + | +35 | pub Z { + | ^ + | +help: add `struct` here to parse `Z` as a public struct + | +35 | pub struct Z { + | ^^^^^^ + +error: aborting due to 7 previous errors + From c82e9e8e1e634250b901b69808f65fbe5f3312c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 21 Nov 2017 08:03:02 -0800 Subject: [PATCH 04/10] Do not attemt to continue parsing after `pub ident` Try to identify the following code in order to provide better diagnostics, but return the error to bail out early during the parse. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/def_collector.rs | 1 - src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 3 +- src/librustc_save_analysis/sig.rs | 1 - src/libsyntax/ast.rs | 2 - src/libsyntax/fold.rs | 1 - src/libsyntax/parse/parser.rs | 128 ++++-------------- src/libsyntax/print/pprust.rs | 6 - src/libsyntax/visit.rs | 1 - src/test/ui/pub/pub-restricted-error.rs | 2 +- ...kw-unclosed-block.rs => pub-ident-fn-2.rs} | 30 +--- src/test/ui/suggestions/pub-ident-fn-2.stderr | 13 ++ ...sing-kw.rs => pub-ident-fn-or-struct-2.rs} | 30 +--- .../pub-ident-fn-or-struct-2.stderr | 8 ++ .../ui/suggestions/pub-ident-fn-or-struct.rs | 13 ++ .../suggestions/pub-ident-fn-or-struct.stderr | 8 ++ ...pub-ident-missing-kw-unclosed-block.stderr | 36 ----- .../suggestions/pub-ident-missing-kw.stderr | 69 ---------- 19 files changed, 74 insertions(+), 282 deletions(-) rename src/test/ui/suggestions/{pub-ident-missing-kw-unclosed-block.rs => pub-ident-fn-2.rs} (70%) create mode 100644 src/test/ui/suggestions/pub-ident-fn-2.stderr rename src/test/ui/suggestions/{pub-ident-missing-kw.rs => pub-ident-fn-or-struct-2.rs} (70%) create mode 100644 src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr create mode 100644 src/test/ui/suggestions/pub-ident-fn-or-struct.rs create mode 100644 src/test/ui/suggestions/pub-ident-fn-or-struct.stderr delete mode 100644 src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr delete mode 100644 src/test/ui/suggestions/pub-ident-missing-kw.stderr diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0fd2ae9dbc8aa..eafc6e0decf67 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1757,7 +1757,7 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::Placeholder | ItemKind::MacroDef(..) | ItemKind::Mac(..) => { + ItemKind::MacroDef(..) | ItemKind::Mac(..) => { panic!("Shouldn't still be around") } } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index c2dd7edbb1053..d8590c1de94e9 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -113,7 +113,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { return visit::walk_item(self, i); } ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), - ItemKind::Placeholder | ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1492c817ffd39..46513a5740aed 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -269,7 +269,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, imported_binding); } - ItemKind::GlobalAsm(..) | ItemKind::Placeholder => {} + ItemKind::GlobalAsm(..) => {} ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 64d242307a7d8..ae92cb81e273e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1947,8 +1947,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) | - ItemKind::Placeholder => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => { // do nothing, these are just around to be encoded } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index e7cf5782290ad..b244876226c48 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -548,7 +548,6 @@ impl Sig for ast::Item { // FIXME should implement this (e.g., pub use). ast::ItemKind::Use(_) => Err("import"), ast::ItemKind::Mac(..) | ast::ItemKind::MacroDef(_) => Err("Macro"), - ast::ItemKind::Placeholder => Err("placeholder"), } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a09cfbec879aa..ad9d58651207d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1977,7 +1977,6 @@ pub enum ItemKind { /// A macro definition. MacroDef(MacroDef), - Placeholder, } impl ItemKind { @@ -1999,7 +1998,6 @@ impl ItemKind { ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl(..) | - ItemKind::Placeholder | ItemKind::AutoImpl(..) => "item" } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 40370eb809688..cc63bffec48a1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -935,7 +935,6 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)), - ItemKind::Placeholder => ItemKind::Placeholder, } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0eda8e4d66b31..f839a83985315 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -72,50 +72,6 @@ bitflags! { type ItemInfo = (Ident, ItemKind, Option >); -enum HasRecovered<'a, T> { - Success(T), - Recovered(T, DiagnosticBuilder<'a>), -} - -impl<'a, T> HasRecovered<'a, T> { - fn new(t: T, err: Option>) -> HasRecovered<'a, T> { - if let Some(err) = err { - HasRecovered::Recovered(t, err) - } else { - HasRecovered::Success(t) - } - } - - fn map O>(self, f: F) -> HasRecovered<'a, O> { - let (t, e) = self.full_unwrap(); - HasRecovered::new(f(t), e) - } - - fn emit(self) -> T { - match self { - HasRecovered::Recovered(t, mut err) => { - err.emit(); - t - } - HasRecovered::Success(t) => t, - } - } - - fn full_unwrap(self) -> (T, Option>) { - match self { - HasRecovered::Recovered(t, err) => (t, Some(err)), - HasRecovered::Success(t) => (t, None), - } - } - - fn into_result(self) -> PResult<'a, T> { - match self { - HasRecovered::Recovered(_, err) => Err(err), - HasRecovered::Success(t) => Ok(t), - } - } -} - /// How to parse a path. #[derive(Copy, Clone, PartialEq)] pub enum PathStyle { @@ -1411,7 +1367,6 @@ impl<'a> Parser<'a> { debug!("parse_trait_methods(): parsing provided method"); *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let body = body.emit(); attrs.extend(inner_attrs.iter().cloned()); Some(body) } @@ -2447,7 +2402,7 @@ impl<'a> Parser<'a> { let mut attrs = outer_attrs; attrs.extend(self.parse_inner_attributes()?); - let blk = self.parse_block_tail(lo, blk_mode)?.emit(); + let blk = self.parse_block_tail(lo, blk_mode)?; return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } @@ -3204,7 +3159,7 @@ impl<'a> Parser<'a> { let hi = self.prev_span; Ok(self.mk_expr(span_lo.to(hi), - ExprKind::ForLoop(pat, expr, loop_block.emit(), opt_ident), + ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } @@ -3217,7 +3172,6 @@ impl<'a> Parser<'a> { } let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let body = body.emit(); attrs.extend(iattrs); let span = span_lo.to(body.span); return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); @@ -3233,7 +3187,6 @@ impl<'a> Parser<'a> { let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let body = body.emit(); let span = span_lo.to(body.span); return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } @@ -3243,7 +3196,6 @@ impl<'a> Parser<'a> { span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let body = body.emit(); attrs.extend(iattrs); let span = span_lo.to(body.span); Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) @@ -3254,7 +3206,6 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; - let body = body.emit(); attrs.extend(iattrs); Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } @@ -4301,14 +4252,14 @@ impl<'a> Parser<'a> { return Err(e); } - Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?.emit()) + Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?) } /// Parse a block. Inner attrs are allowed. fn parse_inner_attrs_and_block(&mut self) - -> PResult<'a, (Vec, HasRecovered<'a, P>)> + -> PResult<'a, (Vec, P)> { - maybe_whole!(self, NtBlock, |x| (Vec::new(), HasRecovered::Success(x))); + maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; @@ -4319,15 +4270,14 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) - -> PResult<'a, HasRecovered<'a, P>> + -> PResult<'a, P> { let mut stmts = vec![]; - let mut error = None; while !self.eat(&token::CloseDelim(token::Brace)) { let stmt = match self.parse_full_stmt(false) { - Err(err) => { - error = Some(err); + Err(mut err) => { + err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break); break; } @@ -4342,14 +4292,12 @@ impl<'a> Parser<'a> { continue; }; } - let block = HasRecovered::new(P(ast::Block { + Ok(P(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span), - }), error); - - Ok(block) + })) } /// Parse a statement, including the trailing semicolon. @@ -4984,22 +4932,11 @@ impl<'a> Parser<'a> { constness: Spanned, abi: abi::Abi) -> PResult<'a, ItemInfo> { - - self.parse_item_fn_recoverable(unsafety, constness, abi)?.into_result() - } - - fn parse_item_fn_recoverable(&mut self, - unsafety: Unsafety, - constness: Spanned, - abi: abi::Abi) - -> PResult<'a, HasRecovered<'a, ItemInfo>> { let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(false)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - Ok(body.map(|body| (ident, - ItemKind::Fn(decl, unsafety, constness, abi, generics, body), - Some(inner_attrs)))) + Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs))) } /// true if we are looking at `const ID`, false for things like `const fn` etc @@ -5183,7 +5120,6 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let body = body.into_result()?; Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig { abi, unsafety, @@ -6369,49 +6305,31 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic() .struct_span_err(sp, "missing `struct` for struct definition"); err.span_suggestion_short(sp, &msg, " struct ".into()); - err.emit(); - self.consume_block(token::Brace); - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - ItemKind::Placeholder, - visibility, - vec![]); - return Ok(Some(item)); + return Err(err); } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { let ident = self.parse_ident().unwrap(); self.consume_block(token::Paren); - let (kw, ambiguous) = if self.check(&token::OpenDelim(token::Brace)) { - self.consume_block(token::Brace); - ("fn", false) + let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) || + self.check(&token::OpenDelim(token::Brace)) + { + ("fn", "method", false) } else if self.check(&token::Colon) { let kw = "struct"; - (kw, false) + (kw, kw, false) } else { - ("fn` or `struct", true) + ("fn` or `struct", "method or struct", true) }; - let msg = format!("missing `{}`{}", kw, - if ambiguous { - "".to_string() - } else { - format!(" for {} definition", kw) - }); + let msg = format!("missing `{}` for {} definition", kw, kw_name); let mut err = self.diagnostic().struct_span_err(sp, &msg); if !ambiguous { - let suggestion = format!("add `{kw}` here to parse `{}` as a public {kw}", + let suggestion = format!("add `{}` here to parse `{}` as a public {}", + kw, ident, - kw=kw); + kw_name); err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw)); } - err.emit(); - let prev_span = self.prev_span; - let item = self.mk_item(lo.to(prev_span), - ident, - ItemKind::Placeholder, - visibility, - vec![]); - return Ok(Some(item)); + return Err(err); } } self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 926bdd2a95776..38627b40544f5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1386,12 +1386,6 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; } - ast::ItemKind::Placeholder => { - self.s.word("")?; - self.end()?; - } } self.ann.post(self, NodeItem(item)) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5a6fbe0a8f89a..c2e90f0bb13a3 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -307,7 +307,6 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), - ItemKind::Placeholder => (), } walk_list!(visitor, visit_attribute, &item.attrs); } diff --git a/src/test/ui/pub/pub-restricted-error.rs b/src/test/ui/pub/pub-restricted-error.rs index 99af031899ab6..7f300ed234253 100644 --- a/src/test/ui/pub/pub-restricted-error.rs +++ b/src/test/ui/pub/pub-restricted-error.rs @@ -16,4 +16,4 @@ struct Foo { pub(crate) () foo: usize, } - +fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs b/src/test/ui/suggestions/pub-ident-fn-2.rs similarity index 70% rename from src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs rename to src/test/ui/suggestions/pub-ident-fn-2.rs index ceaaa0315d2e0..40c50a4b8dd92 100644 --- a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.rs +++ b/src/test/ui/suggestions/pub-ident-fn-2.rs @@ -8,32 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub Struct { - y: usize, -} - -pub Y { - x: usize, - - -pub struct X { - foo(); -} - -pub Z { - x->foo(), -} - -pub foo(foo) { - foo -} +pub foo(s: usize) { bar() } -pub struct X { - foo(); +fn main() { + foo(2); } - -pub Z { - x->foo(), -} - -fn main(){} diff --git a/src/test/ui/suggestions/pub-ident-fn-2.stderr b/src/test/ui/suggestions/pub-ident-fn-2.stderr new file mode 100644 index 0000000000000..43b81efbf4ce5 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn-2.stderr @@ -0,0 +1,13 @@ +error: missing `fn` for method definition + --> $DIR/pub-ident-fn-2.rs:11:4 + | +11 | pub foo(s: usize) { bar() } + | ^ + | +help: add `fn` here to parse `foo` as a public method + | +11 | pub fn foo(s: usize) { bar() } + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/pub-ident-missing-kw.rs b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs similarity index 70% rename from src/test/ui/suggestions/pub-ident-missing-kw.rs rename to src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs index e2a7c394ec94b..6b5ae19e6ff98 100644 --- a/src/test/ui/suggestions/pub-ident-missing-kw.rs +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs @@ -8,32 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub Struct { - y: usize, -} +pub S(); -pub Y { - x: usize, -} - -pub struct X { - foo(); -} - -pub Z { - x->foo(), -} - -pub foo(foo) { - foo -} - -pub struct X { - foo(); -} - -pub Z { - x->foo(), -} - -fn main(){} +fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr new file mode 100644 index 0000000000000..e8636f67e0bfb --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr @@ -0,0 +1,8 @@ +error: missing `fn` or `struct` for method or struct definition + --> $DIR/pub-ident-fn-or-struct-2.rs:11:4 + | +11 | pub S(); + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.rs b/src/test/ui/suggestions/pub-ident-fn-or-struct.rs new file mode 100644 index 0000000000000..8bb1c6afcbb13 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub S (foo) bar + +fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr b/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr new file mode 100644 index 0000000000000..dc391c1113d11 --- /dev/null +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr @@ -0,0 +1,8 @@ +error: missing `fn` or `struct` for method or struct definition + --> $DIR/pub-ident-fn-or-struct.rs:11:4 + | +11 | pub S (foo) bar + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr b/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr deleted file mode 100644 index a580aaac8deba..0000000000000 --- a/src/test/ui/suggestions/pub-ident-missing-kw-unclosed-block.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error: this file contains an un-closed delimiter - --> $DIR/pub-ident-missing-kw-unclosed-block.rs:29:13 - | -39 | fn main(){} - | ^ - | -help: did you mean to close this delimiter? - --> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:7 - | -15 | pub Y { - | ^ - -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw-unclosed-block.rs:1:4 - | -11 | pub Struct { - | ^ - | -help: add `struct` here to parse `Struct` as a public struct - | -11 | pub struct Struct { - | ^^^^^^ - -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw-unclosed-block.rs:5:4 - | -15 | pub Y { - | ^ - | -help: add `struct` here to parse `Y` as a public struct - | -15 | pub struct Y { - | ^^^^^^ - -error: aborting due to 3 previous errors - diff --git a/src/test/ui/suggestions/pub-ident-missing-kw.stderr b/src/test/ui/suggestions/pub-ident-missing-kw.stderr deleted file mode 100644 index 23ac4eca2b42f..0000000000000 --- a/src/test/ui/suggestions/pub-ident-missing-kw.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw.rs:11:4 - | -11 | pub Struct { - | ^ - | -help: add `struct` here to parse `Struct` as a public struct - | -11 | pub struct Struct { - | ^^^^^^ - -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw.rs:15:4 - | -15 | pub Y { - | ^ - | -help: add `struct` here to parse `Y` as a public struct - | -15 | pub struct Y { - | ^^^^^^ - -error: expected `:`, found `(` - --> $DIR/pub-ident-missing-kw.rs:20:8 - | -20 | foo(); - | ^ - -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw.rs:23:4 - | -23 | pub Z { - | ^ - | -help: add `struct` here to parse `Z` as a public struct - | -23 | pub struct Z { - | ^^^^^^ - -error: missing `fn` for fn definition - --> $DIR/pub-ident-missing-kw.rs:27:4 - | -27 | pub foo(foo) { - | ^ - | -help: add `fn` here to parse `foo` as a public fn - | -27 | pub fn foo(foo) { - | ^^ - -error: expected `:`, found `(` - --> $DIR/pub-ident-missing-kw.rs:32:8 - | -32 | foo(); - | ^ - -error: missing `struct` for struct definition - --> $DIR/pub-ident-missing-kw.rs:35:4 - | -35 | pub Z { - | ^ - | -help: add `struct` here to parse `Z` as a public struct - | -35 | pub struct Z { - | ^^^^^^ - -error: aborting due to 7 previous errors - From df357b20be69d799fb9d562c33cbb98a03c64ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 Nov 2017 09:49:27 -0800 Subject: [PATCH 05/10] Suggest macro call when not sure that it is fn definition --- src/libsyntax/parse/parser.rs | 35 +++++++++---------- src/test/parse-fail/doc-after-struct-field.rs | 2 +- .../parse-fail/doc-before-struct-rbrace-1.rs | 2 +- .../parse-fail/doc-before-struct-rbrace-2.rs | 2 +- src/test/parse-fail/issue-22647.rs | 1 + src/test/parse-fail/issue-22712.rs | 2 +- src/test/parse-fail/issue-24197.rs | 2 +- src/test/parse-fail/mut-patterns.rs | 1 + src/test/parse-fail/pat-lt-bracket-5.rs | 4 +-- src/test/parse-fail/pat-ranges-1.rs | 2 +- src/test/parse-fail/pat-ranges-2.rs | 2 +- src/test/parse-fail/pat-ranges-3.rs | 2 +- src/test/parse-fail/pat-ranges-4.rs | 2 +- src/test/parse-fail/range-3.rs | 2 +- src/test/parse-fail/range-4.rs | 2 +- src/test/ui/suggestions/pub-ident-fn-2.stderr | 1 - .../pub-ident-fn-or-struct-2.stderr | 2 +- .../suggestions/pub-ident-fn-or-struct.stderr | 2 +- src/test/ui/suggestions/pub-ident-fn.stderr | 1 - .../ui/suggestions/pub-ident-struct.stderr | 1 - 20 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f839a83985315..be7e589f4ad7c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3158,9 +3158,7 @@ impl<'a> Parser<'a> { attrs.extend(iattrs); let hi = self.prev_span; - Ok(self.mk_expr(span_lo.to(hi), - ExprKind::ForLoop(pat, expr, loop_block, opt_ident), - attrs)) + Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) @@ -4252,13 +4250,11 @@ impl<'a> Parser<'a> { return Err(e); } - Ok(self.parse_block_tail(lo, BlockCheckMode::Default)?) + self.parse_block_tail(lo, BlockCheckMode::Default) } /// Parse a block. Inner attrs are allowed. - fn parse_inner_attrs_and_block(&mut self) - -> PResult<'a, (Vec, P)> - { + fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); let lo = self.span; @@ -4269,9 +4265,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) - -> PResult<'a, P> - { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { @@ -5340,32 +5334,23 @@ impl<'a> Parser<'a> { } fn consume_block(&mut self, delim: token::DelimToken) { - debug!("consuming {:?}", delim); - debug!("self.token {:?}", self.token); let mut brace_depth = 0; if !self.eat(&token::OpenDelim(delim)) { - debug!("didn't eat delim"); return; } loop { if self.eat(&token::OpenDelim(delim)) { - debug!("add depth"); brace_depth += 1; } else if self.eat(&token::CloseDelim(delim)) { - debug!("found closing"); if brace_depth == 0 { - debug!("ending"); return; } else { - debug!("decrease"); brace_depth -= 1; continue; } } else if self.eat(&token::Eof) || self.eat(&token::CloseDelim(token::NoDelim)) { - debug!("eof or nodelim"); return; } else { - debug!("bump"); self.bump(); } } @@ -6297,6 +6282,8 @@ impl<'a> Parser<'a> { // pub S {} // ^^^ `sp` points here let sp = self.prev_span.between(self.span); + let full_sp = self.prev_span.to(self.span); + let ident_sp = self.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(); @@ -6328,6 +6315,16 @@ impl<'a> Parser<'a> { ident, kw_name); err.span_suggestion_short(sp, &suggestion, format!(" {} ", kw)); + } else { + if let Ok(snippet) = self.sess.codemap().span_to_snippet(ident_sp) { + err.span_suggestion( + full_sp, + "if you meant to call a macro, write instead", + format!("{}!", snippet)); + } else { + err.help("if you meant to call a macro, remove the `pub` \ + and add a trailing `!` after the identifier"); + } } return Err(err); } diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs index 1aa6af5b78f5b..8babf4daaddcc 100644 --- a/src/test/parse-fail/doc-after-struct-field.rs +++ b/src/test/parse-fail/doc-after-struct-field.rs @@ -16,5 +16,5 @@ struct X { } fn main() { - let y = X {a = 1}; + let y = X {a: 1}; } diff --git a/src/test/parse-fail/doc-before-struct-rbrace-1.rs b/src/test/parse-fail/doc-before-struct-rbrace-1.rs index 5ba83190c8e50..6d9b4b05ad9fa 100644 --- a/src/test/parse-fail/doc-before-struct-rbrace-1.rs +++ b/src/test/parse-fail/doc-before-struct-rbrace-1.rs @@ -17,5 +17,5 @@ struct X { } fn main() { - let y = X {a = 1}; + let y = X {a: 1}; } diff --git a/src/test/parse-fail/doc-before-struct-rbrace-2.rs b/src/test/parse-fail/doc-before-struct-rbrace-2.rs index 643e4aa17a1ac..63b2f96379916 100644 --- a/src/test/parse-fail/doc-before-struct-rbrace-2.rs +++ b/src/test/parse-fail/doc-before-struct-rbrace-2.rs @@ -16,5 +16,5 @@ struct X { } fn main() { - let y = X {a = 1}; + let y = X {a: 1}; } diff --git a/src/test/parse-fail/issue-22647.rs b/src/test/parse-fail/issue-22647.rs index 1ace57edba3d8..3da9d1a8712ad 100644 --- a/src/test/parse-fail/issue-22647.rs +++ b/src/test/parse-fail/issue-22647.rs @@ -16,6 +16,7 @@ fn main() { println!("Y {}",x); return x; }; + //~^ ERROR expected item, found `;` caller(bar_handler); } diff --git a/src/test/parse-fail/issue-22712.rs b/src/test/parse-fail/issue-22712.rs index ed936cdd9a934..84d4a757a0776 100644 --- a/src/test/parse-fail/issue-22712.rs +++ b/src/test/parse-fail/issue-22712.rs @@ -14,6 +14,6 @@ struct Foo { fn bar() { let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` -} +} //~ ERROR expected item, found `}` fn main() {} diff --git a/src/test/parse-fail/issue-24197.rs b/src/test/parse-fail/issue-24197.rs index 37d6218261234..b6bc3a29e0691 100644 --- a/src/test/parse-fail/issue-24197.rs +++ b/src/test/parse-fail/issue-24197.rs @@ -10,4 +10,4 @@ fn main() { let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/mut-patterns.rs b/src/test/parse-fail/mut-patterns.rs index 71d826c67f8bd..ffb455975521a 100644 --- a/src/test/parse-fail/mut-patterns.rs +++ b/src/test/parse-fail/mut-patterns.rs @@ -15,4 +15,5 @@ pub fn main() { struct Foo { x: isize } let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` + //~^ ERROR expected item, found `=` } diff --git a/src/test/parse-fail/pat-lt-bracket-5.rs b/src/test/parse-fail/pat-lt-bracket-5.rs index 3345845eee9ae..95ad006402ea6 100644 --- a/src/test/parse-fail/pat-lt-bracket-5.rs +++ b/src/test/parse-fail/pat-lt-bracket-5.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let v[0] = v[1]; //~ error: expected one of `:`, `;`, `=`, or `@`, found `[` -} + let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/pat-ranges-1.rs b/src/test/parse-fail/pat-ranges-1.rs index 857a3924aec01..7a42f453c74df 100644 --- a/src/test/parse-fail/pat-ranges-1.rs +++ b/src/test/parse-fail/pat-ranges-1.rs @@ -12,4 +12,4 @@ fn main() { let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/pat-ranges-2.rs b/src/test/parse-fail/pat-ranges-2.rs index 64c749333cf4a..ad0a3b3b67fc5 100644 --- a/src/test/parse-fail/pat-ranges-2.rs +++ b/src/test/parse-fail/pat-ranges-2.rs @@ -12,4 +12,4 @@ fn main() { let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/pat-ranges-3.rs b/src/test/parse-fail/pat-ranges-3.rs index 1327a9fab3661..4a9a12bcdd26e 100644 --- a/src/test/parse-fail/pat-ranges-3.rs +++ b/src/test/parse-fail/pat-ranges-3.rs @@ -12,4 +12,4 @@ fn main() { let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/pat-ranges-4.rs b/src/test/parse-fail/pat-ranges-4.rs index c159c7702502d..32fdc263b2d47 100644 --- a/src/test/parse-fail/pat-ranges-4.rs +++ b/src/test/parse-fail/pat-ranges-4.rs @@ -13,4 +13,4 @@ fn main() { let 10 - 3 ..= 10 = 8; //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/range-3.rs b/src/test/parse-fail/range-3.rs index 95aa71b0cdfdb..f413ac340877b 100644 --- a/src/test/parse-fail/range-3.rs +++ b/src/test/parse-fail/range-3.rs @@ -15,4 +15,4 @@ pub fn main() { let r = 1..2..3; //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/parse-fail/range-4.rs b/src/test/parse-fail/range-4.rs index 4500df116a2de..0b385129b2386 100644 --- a/src/test/parse-fail/range-4.rs +++ b/src/test/parse-fail/range-4.rs @@ -15,4 +15,4 @@ pub fn main() { let r = ..1..2; //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` -} +} //~ ERROR expected item, found `}` diff --git a/src/test/ui/suggestions/pub-ident-fn-2.stderr b/src/test/ui/suggestions/pub-ident-fn-2.stderr index 43b81efbf4ce5..7d3abceb11b58 100644 --- a/src/test/ui/suggestions/pub-ident-fn-2.stderr +++ b/src/test/ui/suggestions/pub-ident-fn-2.stderr @@ -3,7 +3,6 @@ error: missing `fn` for method definition | 11 | pub foo(s: usize) { bar() } | ^ - | help: add `fn` here to parse `foo` as a public method | 11 | pub fn foo(s: usize) { bar() } diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr index e8636f67e0bfb..68dea2aec3a54 100644 --- a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.stderr @@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition --> $DIR/pub-ident-fn-or-struct-2.rs:11:4 | 11 | pub S(); - | ^ + | ---^- help: if you meant to call a macro, write instead: `S!` error: aborting due to previous error diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr b/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr index dc391c1113d11..0c19f776bd18e 100644 --- a/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct.stderr @@ -2,7 +2,7 @@ error: missing `fn` or `struct` for method or struct definition --> $DIR/pub-ident-fn-or-struct.rs:11:4 | 11 | pub S (foo) bar - | ^ + | ---^- help: if you meant to call a macro, write instead: `S!` error: aborting due to previous error diff --git a/src/test/ui/suggestions/pub-ident-fn.stderr b/src/test/ui/suggestions/pub-ident-fn.stderr index 19d3db157c239..d36b9b127e0c1 100644 --- a/src/test/ui/suggestions/pub-ident-fn.stderr +++ b/src/test/ui/suggestions/pub-ident-fn.stderr @@ -3,7 +3,6 @@ error: missing `fn` for method definition | 11 | pub foo(s: usize) -> bool { true } | ^^^ - | help: add `fn` here to parse `foo` as a public method | 11 | pub fn foo(s: usize) -> bool { true } diff --git a/src/test/ui/suggestions/pub-ident-struct.stderr b/src/test/ui/suggestions/pub-ident-struct.stderr index bae2f6a4f809d..36ef307272231 100644 --- a/src/test/ui/suggestions/pub-ident-struct.stderr +++ b/src/test/ui/suggestions/pub-ident-struct.stderr @@ -3,7 +3,6 @@ error: missing `struct` for struct definition | 11 | pub S { | ^ - | help: add `struct` here to parse `S` as a public struct | 11 | pub struct S { From 4e2d1b946696357d7a57dcc6dfd47c42f91c3c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Nov 2017 13:15:31 -0800 Subject: [PATCH 06/10] Emit `DocComment` in bad location error but continue parsing struct fields --- src/libsyntax/parse/parser.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index be7e589f4ad7c..07b918da0d11c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5419,8 +5419,16 @@ impl<'a> Parser<'a> { self.bump(); } token::CloseDelim(token::Brace) => {} - token::DocComment(_) => return Err(self.span_fatal_err(self.span, - Error::UselessDocComment)), + token::DocComment(_) => { + let mut err = self.span_fatal_err(self.span, Error::UselessDocComment); + if self.eat(&token::Comma) || + self.look_ahead(1, |t| *t == token::CloseDelim(token::Brace)) + { + err.emit(); + } else { + return Err(err); + } + } _ => return Err(self.span_fatal_help(self.span, &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()), "struct fields should be separated by commas")), From 0e93b75d27050e175c8ca1b401fa2f69378b378a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Nov 2017 13:16:19 -0800 Subject: [PATCH 07/10] Revert to correct recovery behavior --- src/libsyntax/parse/parser.rs | 1 + src/test/parse-fail/issue-22712.rs | 2 +- src/test/parse-fail/issue-24197.rs | 2 +- src/test/parse-fail/pat-lt-bracket-5.rs | 2 +- src/test/parse-fail/pat-ranges-1.rs | 2 +- src/test/parse-fail/pat-ranges-2.rs | 2 +- src/test/parse-fail/pat-ranges-3.rs | 2 +- src/test/parse-fail/pat-ranges-4.rs | 2 +- src/test/parse-fail/range-3.rs | 2 +- src/test/parse-fail/range-4.rs | 2 +- 10 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 07b918da0d11c..d3104e0a553c3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4273,6 +4273,7 @@ impl<'a> Parser<'a> { Err(mut err) => { err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Break); + self.eat(&token::CloseDelim(token::Brace)); break; } Ok(stmt) => stmt, diff --git a/src/test/parse-fail/issue-22712.rs b/src/test/parse-fail/issue-22712.rs index 84d4a757a0776..ed936cdd9a934 100644 --- a/src/test/parse-fail/issue-22712.rs +++ b/src/test/parse-fail/issue-22712.rs @@ -14,6 +14,6 @@ struct Foo { fn bar() { let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` -} //~ ERROR expected item, found `}` +} fn main() {} diff --git a/src/test/parse-fail/issue-24197.rs b/src/test/parse-fail/issue-24197.rs index b6bc3a29e0691..37d6218261234 100644 --- a/src/test/parse-fail/issue-24197.rs +++ b/src/test/parse-fail/issue-24197.rs @@ -10,4 +10,4 @@ fn main() { let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/pat-lt-bracket-5.rs b/src/test/parse-fail/pat-lt-bracket-5.rs index 95ad006402ea6..421d7a05befff 100644 --- a/src/test/parse-fail/pat-lt-bracket-5.rs +++ b/src/test/parse-fail/pat-lt-bracket-5.rs @@ -10,4 +10,4 @@ fn main() { let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/pat-ranges-1.rs b/src/test/parse-fail/pat-ranges-1.rs index 7a42f453c74df..857a3924aec01 100644 --- a/src/test/parse-fail/pat-ranges-1.rs +++ b/src/test/parse-fail/pat-ranges-1.rs @@ -12,4 +12,4 @@ fn main() { let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/pat-ranges-2.rs b/src/test/parse-fail/pat-ranges-2.rs index ad0a3b3b67fc5..64c749333cf4a 100644 --- a/src/test/parse-fail/pat-ranges-2.rs +++ b/src/test/parse-fail/pat-ranges-2.rs @@ -12,4 +12,4 @@ fn main() { let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/pat-ranges-3.rs b/src/test/parse-fail/pat-ranges-3.rs index 4a9a12bcdd26e..1327a9fab3661 100644 --- a/src/test/parse-fail/pat-ranges-3.rs +++ b/src/test/parse-fail/pat-ranges-3.rs @@ -12,4 +12,4 @@ fn main() { let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/pat-ranges-4.rs b/src/test/parse-fail/pat-ranges-4.rs index 32fdc263b2d47..c159c7702502d 100644 --- a/src/test/parse-fail/pat-ranges-4.rs +++ b/src/test/parse-fail/pat-ranges-4.rs @@ -13,4 +13,4 @@ fn main() { let 10 - 3 ..= 10 = 8; //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/range-3.rs b/src/test/parse-fail/range-3.rs index f413ac340877b..95aa71b0cdfdb 100644 --- a/src/test/parse-fail/range-3.rs +++ b/src/test/parse-fail/range-3.rs @@ -15,4 +15,4 @@ pub fn main() { let r = 1..2..3; //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` -} //~ ERROR expected item, found `}` +} diff --git a/src/test/parse-fail/range-4.rs b/src/test/parse-fail/range-4.rs index 0b385129b2386..4500df116a2de 100644 --- a/src/test/parse-fail/range-4.rs +++ b/src/test/parse-fail/range-4.rs @@ -15,4 +15,4 @@ pub fn main() { let r = ..1..2; //~^ ERROR expected one of `.`, `;`, `?`, or an operator, found `..` -} //~ ERROR expected item, found `}` +} From f103342b8f63e6e88992749b5d0a49995bad5d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Nov 2017 07:34:24 -0800 Subject: [PATCH 08/10] Consume trailing doc comments to avoid parse errors --- src/libsyntax/parse/parser.rs | 5 ++--- src/test/parse-fail/doc-after-struct-field.rs | 10 +++++++++- src/test/parse-fail/issue-37234.rs | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d3104e0a553c3..e88c3c828db65 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5422,9 +5422,8 @@ impl<'a> Parser<'a> { token::CloseDelim(token::Brace) => {} token::DocComment(_) => { let mut err = self.span_fatal_err(self.span, Error::UselessDocComment); - if self.eat(&token::Comma) || - self.look_ahead(1, |t| *t == token::CloseDelim(token::Brace)) - { + self.bump(); // consume the doc comment + if self.eat(&token::Comma) || self.token == token::CloseDelim(token::Brace) { err.emit(); } else { return Err(err); diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs index 8babf4daaddcc..a2c60151ac72d 100644 --- a/src/test/parse-fail/doc-after-struct-field.rs +++ b/src/test/parse-fail/doc-after-struct-field.rs @@ -9,12 +9,20 @@ // except according to those terms. // compile-flags: -Z continue-parse-after-error + struct X { a: u8 /** document a */, //~^ ERROR found a documentation comment that doesn't document anything //~| HELP maybe a comment was intended } +struct Y { + a: u8 /// document a + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended +} + fn main() { - let y = X {a: 1}; + let x = X { a: 1 }; + let y = Y { a: 1 }; } diff --git a/src/test/parse-fail/issue-37234.rs b/src/test/parse-fail/issue-37234.rs index 651e11d9d21b3..93a1468bf7b19 100644 --- a/src/test/parse-fail/issue-37234.rs +++ b/src/test/parse-fail/issue-37234.rs @@ -11,7 +11,7 @@ macro_rules! failed { () => {{ let x = 5 ""; //~ ERROR found `""` - }} //~ ERROR macro expansion ignores token `}` + }} } fn main() { From 0e241d0059b0d2c2b1dc66883c1e1ebc8b474111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Nov 2017 06:26:46 -0800 Subject: [PATCH 09/10] Add inline `compile-fail` markers to tests --- src/test/ui/suggestions/pub-ident-fn-2.rs | 1 + src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs | 1 + src/test/ui/suggestions/pub-ident-fn-or-struct.rs | 1 + src/test/ui/suggestions/pub-ident-fn.rs | 1 + src/test/ui/suggestions/pub-ident-struct.rs | 1 + 5 files changed, 5 insertions(+) diff --git a/src/test/ui/suggestions/pub-ident-fn-2.rs b/src/test/ui/suggestions/pub-ident-fn-2.rs index 40c50a4b8dd92..44884bfcdfdce 100644 --- a/src/test/ui/suggestions/pub-ident-fn-2.rs +++ b/src/test/ui/suggestions/pub-ident-fn-2.rs @@ -9,6 +9,7 @@ // except according to those terms. pub foo(s: usize) { bar() } +//~^ ERROR missing `fn` for method definition fn main() { foo(2); diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs index 6b5ae19e6ff98..1ccadc8a40b72 100644 --- a/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct-2.rs @@ -9,5 +9,6 @@ // except according to those terms. pub S(); +//~^ ERROR missing `fn` or `struct` for method or struct definition fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-fn-or-struct.rs b/src/test/ui/suggestions/pub-ident-fn-or-struct.rs index 8bb1c6afcbb13..0664918945b43 100644 --- a/src/test/ui/suggestions/pub-ident-fn-or-struct.rs +++ b/src/test/ui/suggestions/pub-ident-fn-or-struct.rs @@ -9,5 +9,6 @@ // except according to those terms. pub S (foo) bar +//~^ ERROR missing `fn` or `struct` for method or struct definition fn main() {} diff --git a/src/test/ui/suggestions/pub-ident-fn.rs b/src/test/ui/suggestions/pub-ident-fn.rs index 043cf9328c920..1d64199642093 100644 --- a/src/test/ui/suggestions/pub-ident-fn.rs +++ b/src/test/ui/suggestions/pub-ident-fn.rs @@ -9,6 +9,7 @@ // except according to those terms. pub foo(s: usize) -> bool { true } +//~^ ERROR missing `fn` for method definition fn main() { foo(2); diff --git a/src/test/ui/suggestions/pub-ident-struct.rs b/src/test/ui/suggestions/pub-ident-struct.rs index 3e14a36dbab63..d08d498f87a01 100644 --- a/src/test/ui/suggestions/pub-ident-struct.rs +++ b/src/test/ui/suggestions/pub-ident-struct.rs @@ -9,5 +9,6 @@ // except according to those terms. pub S { +//~^ ERROR missing `struct` for struct definition } fn main() {} From cf9283ea9376525c59015a52c729e7a79f576426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 25 Nov 2017 08:48:11 -0800 Subject: [PATCH 10/10] Fix proc_macro output with struct parse error --- src/libsyntax_ext/deriving/custom.rs | 8 +++++++- src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index fa5537b5d8fe3..f375847e705bc 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -96,12 +96,18 @@ impl MultiItemModifier for ProcMacroDerive { } }; + let error_count_before = ecx.parse_sess.span_diagnostic.err_count(); __internal::set_sess(ecx, || { + let msg = "proc-macro derive produced unparseable tokens"; match __internal::token_stream_parse_items(stream) { + // fail if there have been errors emitted + Ok(_) if ecx.parse_sess.span_diagnostic.err_count() > error_count_before => { + ecx.struct_span_fatal(span, msg).emit(); + panic!(FatalError); + } Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(), Err(_) => { // FIXME: handle this better - let msg = "proc-macro derive produced unparseable tokens"; ecx.struct_span_fatal(span, msg).emit(); panic!(FatalError); } diff --git a/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs index b03409c9c285e..93790f5937298 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs @@ -17,7 +17,8 @@ extern crate derive_bad; #[derive( A )] -//~^^ ERROR: proc-macro derive produced unparseable tokens +//~^^ ERROR proc-macro derive produced unparseable tokens +//~| ERROR expected `:`, found `}` struct A; fn main() {}