From 053a09529a41931a217daecbe879b88386101249 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 25 Oct 2019 18:30:02 -0700 Subject: Reduce ammount of errors given unclosed delimiter When in a file with a non-terminated item, catch the error and consume the block instead of trying to recover it more granularly in order to reduce the amount of unrelated errors that would be fixed after adding the missing closing brace. Also point out the possible location of the missing closing brace. --- src/libsyntax/parse/parser.rs | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6ead1ce811d..5dbe4d95a85 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::ThinVec; -use errors::{Applicability, DiagnosticId, FatalError}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; @@ -1370,20 +1370,29 @@ impl<'a> Parser<'a> { } } +crate fn make_unclosed_delims_error( + unmatched: UnmatchedBrace, + handler: &errors::Handler, +) -> Option> { + // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to + // `unmatched_braces` only for error recovery in the `Parser`. + let found_delim = unmatched.found_delim?; + let mut err = handler.struct_span_err(unmatched.found_span, &format!( + "incorrect close delimiter: `{}`", + pprust::token_kind_to_string(&token::CloseDelim(found_delim)), + )); + err.span_label(unmatched.found_span, "incorrect close delimiter"); + if let Some(sp) = unmatched.candidate_span { + err.span_label(sp, "close delimiter possibly meant for this"); + } + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "un-closed delimiter"); + } + Some(err) +} + pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { - for unmatched in unclosed_delims.iter() { - let mut err = handler.struct_span_err(unmatched.found_span, &format!( - "incorrect close delimiter: `{}`", - pprust::token_kind_to_string(&token::CloseDelim(unmatched.found_delim)), - )); - err.span_label(unmatched.found_span, "incorrect close delimiter"); - if let Some(sp) = unmatched.candidate_span { - err.span_label(sp, "close delimiter possibly meant for this"); - } - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "un-closed delimiter"); - } - err.emit(); + for unmatched in unclosed_delims.drain(..) { + make_unclosed_delims_error(unmatched, handler).map(|mut e| e.emit()); } - unclosed_delims.clear(); } -- cgit 1.4.1-3-g733a5 From 454e2aa8c99850c9393fb2314e1a71da08120063 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 28 Oct 2019 17:44:20 -0700 Subject: Do not complain about missing `fn main()` in some cases --- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_passes/entry.rs | 9 ++++++- src/libsyntax/parse/mod.rs | 4 ++-- src/libsyntax/parse/parser.rs | 13 +++++----- src/libsyntax/parse/parser/diagnostics.rs | 5 ++++ src/libsyntax/sess.rs | 3 +++ src/test/ui/parser-recovery-1.rs | 1 - src/test/ui/parser-recovery-1.stderr | 26 +++++--------------- src/test/ui/parser/issue-2354.rs | 7 ++---- src/test/ui/parser/issue-2354.stderr | 28 +++------------------- .../missing-close-brace-in-impl-trait.rs | 3 +-- .../missing-close-brace-in-impl-trait.stderr | 25 +++++-------------- .../missing-close-brace-in-struct.rs | 2 +- .../missing-close-brace-in-struct.stderr | 15 +----------- .../missing-close-brace-in-trait.rs | 1 - .../missing-close-brace-in-trait.stderr | 22 ++++------------- 16 files changed, 50 insertions(+), 116 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d942a19194a..cdf5da00606 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -440,7 +440,7 @@ impl cstore::CStore { let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos); let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); - emit_unclosed_delims(&mut errors, &sess.diagnostic()); + emit_unclosed_delims(&mut errors, &sess.parse_sess); // Mark the attrs as used let attrs = data.get_item_attrs(id.index, sess); diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs index bf68807a0c2..66004719060 100644 --- a/src/librustc_passes/entry.rs +++ b/src/librustc_passes/entry.rs @@ -154,6 +154,14 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De } fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { + let sp = tcx.hir().krate().span; + if *tcx.sess.parse_sess.reached_eof.borrow() { + // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about + // the missing `fn main()` then as it might have been hidden inside an unclosed block. + tcx.sess.delay_span_bug(sp, "`main` not found, but expected unclosed brace error"); + return; + } + // There is no main function. let mut err = struct_err!(tcx.sess, E0601, "`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE)); @@ -173,7 +181,6 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { } else { String::from("consider adding a `main` function at the crate level") }; - let sp = tcx.hir().krate().span; // The file may be empty, which leads to the diagnostic machinery not emitting this // note. This is a relatively simple way to detect that case and emit a span-less // note instead. diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 921c4ed0f0a..6d8ecdf805b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -108,7 +108,7 @@ pub fn parse_stream_from_source_str( sess.source_map().new_source_file(name, source), override_span, ); - emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + emit_unclosed_delims(&mut errors, &sess); stream } @@ -242,7 +242,7 @@ pub fn maybe_file_to_stream( err.buffer(&mut buffer); // Not using `emit_unclosed_delims` to use `db.buffer` for unmatched in unmatched_braces { - if let Some(err) = make_unclosed_delims_error(unmatched, &sess.span_diagnostic) { + if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { err.buffer(&mut buffer); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5dbe4d95a85..e81d4573b73 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -148,8 +148,7 @@ pub struct Parser<'a> { impl<'a> Drop for Parser<'a> { fn drop(&mut self) { - let diag = self.diagnostic(); - emit_unclosed_delims(&mut self.unclosed_delims, diag); + emit_unclosed_delims(&mut self.unclosed_delims, &self.sess); } } @@ -1372,12 +1371,12 @@ impl<'a> Parser<'a> { crate fn make_unclosed_delims_error( unmatched: UnmatchedBrace, - handler: &errors::Handler, + sess: &ParseSess, ) -> Option> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to // `unmatched_braces` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; - let mut err = handler.struct_span_err(unmatched.found_span, &format!( + let mut err = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( "incorrect close delimiter: `{}`", pprust::token_kind_to_string(&token::CloseDelim(found_delim)), )); @@ -1391,8 +1390,10 @@ crate fn make_unclosed_delims_error( Some(err) } -pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { +pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &ParseSess) { + *sess.reached_eof.borrow_mut() |= unclosed_delims.iter() + .any(|unmatched_delim| unmatched_delim.found_delim.is_none()); for unmatched in unclosed_delims.drain(..) { - make_unclosed_delims_error(unmatched, handler).map(|mut e| e.emit()); + make_unclosed_delims_error(unmatched, sess).map(|mut e| e.emit()); } } diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index be1441d1c3f..fcf3b4c0aa8 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -1141,6 +1141,11 @@ impl<'a> Parser<'a> { // Don't attempt to recover from this unclosed delimiter more than once. let unmatched = self.unclosed_delims.remove(pos); let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + if unmatched.found_delim.is_none() { + // We encountered `Eof`, set this fact here to avoid complaining about missing + // `fn main()` when we found place to suggest the closing brace. + *self.sess.reached_eof.borrow_mut() = true; + } // We want to suggest the inclusion of the closing delimiter where it makes // the most sense, which is immediately after the last token: diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 28a0868d5dd..323fe01f067 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -73,6 +73,8 @@ pub struct ParseSess { pub ambiguous_block_expr_parse: Lock>, pub injected_crate_name: Once, crate gated_spans: GatedSpans, + /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. + pub reached_eof: Lock, } impl ParseSess { @@ -101,6 +103,7 @@ impl ParseSess { ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), injected_crate_name: Once::new(), gated_spans: GatedSpans::default(), + reached_eof: Lock::new(false), } } diff --git a/src/test/ui/parser-recovery-1.rs b/src/test/ui/parser-recovery-1.rs index 8126525c34f..21d36048e67 100644 --- a/src/test/ui/parser-recovery-1.rs +++ b/src/test/ui/parser-recovery-1.rs @@ -3,7 +3,6 @@ // Test that we can recover from missing braces in the parser. trait Foo { -//~^ ERROR `main` function not found fn bar() { let x = foo(); //~^ ERROR cannot find function `foo` in this scope diff --git a/src/test/ui/parser-recovery-1.stderr b/src/test/ui/parser-recovery-1.stderr index ffe2b3322fc..83f8ef63c99 100644 --- a/src/test/ui/parser-recovery-1.stderr +++ b/src/test/ui/parser-recovery-1.stderr @@ -1,9 +1,8 @@ error: this file contains an un-closed delimiter - --> $DIR/parser-recovery-1.rs:16:55 + --> $DIR/parser-recovery-1.rs:15:55 | LL | trait Foo { | - un-closed delimiter -LL | LL | fn bar() { | - this delimiter might not be properly closed... ... @@ -14,36 +13,23 @@ LL | } | ^ error: unexpected token: `;` - --> $DIR/parser-recovery-1.rs:13:15 + --> $DIR/parser-recovery-1.rs:12:15 | LL | let x = y.; | ^ error[E0425]: cannot find function `foo` in this scope - --> $DIR/parser-recovery-1.rs:8:17 + --> $DIR/parser-recovery-1.rs:7:17 | LL | let x = foo(); | ^^^ not found in this scope error[E0425]: cannot find value `y` in this scope - --> $DIR/parser-recovery-1.rs:13:13 + --> $DIR/parser-recovery-1.rs:12:13 | LL | let x = y.; | ^ not found in this scope -error[E0601]: `main` function not found in crate `parser_recovery_1` - --> $DIR/parser-recovery-1.rs:5:1 - | -LL | / trait Foo { -LL | | -LL | | fn bar() { -LL | | let x = foo(); -... | -LL | | -LL | | } - | |______________________________________________________^ consider adding a `main` function to `$DIR/parser-recovery-1.rs` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0425, E0601. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/issue-2354.rs b/src/test/ui/parser/issue-2354.rs index a14eb6e32fc..c4fc4716182 100644 --- a/src/test/ui/parser/issue-2354.rs +++ b/src/test/ui/parser/issue-2354.rs @@ -1,7 +1,4 @@ fn foo() { //~ NOTE un-closed delimiter -//~^ ERROR `main` function not found -//~^^ NOTE main function must be defined -//~^^^ NOTE you have one or more functions match Some(10) { //~^ NOTE this delimiter might not be properly closed... Some(y) => { panic!(); } @@ -14,5 +11,5 @@ fn bar() { while (i < 1000) {} } -fn main() {} //~ NOTE here is a function named `main` - //~ ERROR this file contains an un-closed delimiter +fn main() {} +//~ ERROR this file contains an un-closed delimiter diff --git a/src/test/ui/parser/issue-2354.stderr b/src/test/ui/parser/issue-2354.stderr index 038e3dcfa40..45199b02cb8 100644 --- a/src/test/ui/parser/issue-2354.stderr +++ b/src/test/ui/parser/issue-2354.stderr @@ -1,9 +1,8 @@ error: this file contains an un-closed delimiter - --> $DIR/issue-2354.rs:18:66 + --> $DIR/issue-2354.rs:15:53 | LL | fn foo() { | - un-closed delimiter -... LL | match Some(10) { | - this delimiter might not be properly closed... ... @@ -11,28 +10,7 @@ LL | } | - ...as it matches this but it has different indentation ... LL | - | ^ - -error[E0601]: `main` function not found in crate `issue_2354` - --> $DIR/issue-2354.rs:1:1 - | -LL | / fn foo() { -LL | | -LL | | -LL | | -... | -LL | | fn main() {} -LL | | - | |_________________________________________________________________^ the main function must be defined at the crate level (in `$DIR/issue-2354.rs`) - | -note: here is a function named `main` - --> $DIR/issue-2354.rs:17:1 - | -LL | fn main() {} - | ^^^^^^^^^^^^ - = note: you have one or more functions named `main` not defined at the crate level - = help: either move the `main` function definitions or attach the `#[main]` attribute to one of them + | ^ -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0601`. 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 66f43889cec..8d89905909e 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,5 +1,4 @@ -impl T for () { //~ ERROR `main` function not found -//~^ ERROR cannot find trait `T` in this scope +impl T for () { //~ ERROR cannot find trait `T` in this scope fn foo(&self) {} 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 52c00758b37..9bf54181a07 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 un-closed delimiter - --> $DIR/missing-close-brace-in-impl-trait.rs:13:53 + --> $DIR/missing-close-brace-in-impl-trait.rs:12:53 | LL | impl T for () { | - un-closed delimiter @@ -7,12 +7,12 @@ LL | impl T for () { LL | | ^ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `trait` - --> $DIR/missing-close-brace-in-impl-trait.rs:6:1 +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 | LL | impl T for () { | - unclosed delimiter -... +LL | LL | fn foo(&self) {} | - | | @@ -28,19 +28,6 @@ error[E0405]: cannot find trait `T` in this scope LL | impl T for () { | ^ not found in this scope -error[E0601]: `main` function not found in crate `missing_close_brace_in_impl_trait` - --> $DIR/missing-close-brace-in-impl-trait.rs:1:1 - | -LL | / impl T for () { -LL | | -LL | | -LL | | fn foo(&self) {} -... | -LL | | fn main() {} -LL | | - | |____________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-impl-trait.rs` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0405, E0601. -For more information about an error, try `rustc --explain E0405`. +For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs index 8f42897914a..5b716b1467c 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs @@ -1,4 +1,4 @@ -pub(crate) struct Bar { //~ ERROR `main` function not found +pub(crate) struct Bar { foo: T, trait T { //~ ERROR expected identifier, found keyword `trait` diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr index e0d5eb90aa1..ce399dbbf45 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr @@ -24,18 +24,5 @@ error: expected `:`, found `T` LL | trait T { | ^ expected `:` -error[E0601]: `main` function not found in crate `missing_close_brace_in_struct` - --> $DIR/missing-close-brace-in-struct.rs:1:1 - | -LL | / pub(crate) struct Bar { -LL | | foo: T, -LL | | -LL | | trait T { -... | -LL | | -LL | | fn main() {} - | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-struct.rs` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0601`. 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 46b9cab66e9..79547195411 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 @@ -1,5 +1,4 @@ trait T { -//~^ ERROR `main` function not found in crate `missing_close_brace_in_trait` fn foo(&self); pub(crate) struct Bar(); //~ ERROR expected one of 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 7de6c1d0cdd..4bfb4c1cb3a 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 @@ -1,5 +1,5 @@ error: this file contains an un-closed delimiter - --> $DIR/missing-close-brace-in-trait.rs:11:66 + --> $DIR/missing-close-brace-in-trait.rs:10:66 | LL | trait T { | - un-closed delimiter @@ -7,12 +7,11 @@ LL | trait T { LL | fn main() {} | ^ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` - --> $DIR/missing-close-brace-in-trait.rs:5:1 +error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found keyword `pub` + --> $DIR/missing-close-brace-in-trait.rs:4:1 | LL | trait T { | - unclosed delimiter -LL | LL | fn foo(&self); | - | | @@ -22,18 +21,5 @@ LL | LL | pub(crate) struct Bar(); | ^^^ unexpected token -error[E0601]: `main` function not found in crate `missing_close_brace_in_trait` - --> $DIR/missing-close-brace-in-trait.rs:1:1 - | -LL | / trait T { -LL | | -LL | | fn foo(&self); -LL | | -... | -LL | | -LL | | fn main() {} - | |_________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-trait.rs` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0601`. -- cgit 1.4.1-3-g733a5