diff --git a/src/librustc_parse/lexer/tokentrees.rs b/src/librustc_parse/lexer/tokentrees.rs index b65b894172844..c08659ec9f648 100644 --- a/src/librustc_parse/lexer/tokentrees.rs +++ b/src/librustc_parse/lexer/tokentrees.rs @@ -1,6 +1,6 @@ use super::{StringReader, UnmatchedBrace}; -use rustc_ast::token::{self, Token}; +use rustc_ast::token::{self, DelimToken, Token}; use rustc_ast::tokenstream::{ DelimSpan, IsJoint::{self, *}, @@ -22,6 +22,7 @@ impl<'a> StringReader<'a> { matching_delim_spans: Vec::new(), last_unclosed_found_span: None, last_delim_empty_block_spans: FxHashMap::default(), + matching_block_spans: Vec::new(), }; let res = tt_reader.parse_all_token_trees(); (res, tt_reader.unmatched_braces) @@ -42,6 +43,9 @@ struct TokenTreesReader<'a> { last_unclosed_found_span: Option, /// Collect empty block spans that might have been auto-inserted by editors. last_delim_empty_block_spans: FxHashMap, + /// Collect the spans of braces (Open, Close). Used only + /// for detecting if blocks are empty and only braces. + matching_block_spans: Vec<(Span, Span)>, } impl<'a> TokenTreesReader<'a> { @@ -77,6 +81,7 @@ impl<'a> TokenTreesReader<'a> { fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { let sm = self.string_reader.sess.source_map(); + match self.token.kind { token::Eof => { let msg = "this file contains an unclosed delimiter"; @@ -146,6 +151,14 @@ impl<'a> TokenTreesReader<'a> { } } + match (open_brace, delim) { + //only add braces + (DelimToken::Brace, DelimToken::Brace) => { + self.matching_block_spans.push((open_brace_span, close_brace_span)); + } + _ => {} + } + if self.open_braces.is_empty() { // Clear up these spans to avoid suggesting them as we've found // properly matched delimiters so far for an entire block. @@ -164,6 +177,7 @@ impl<'a> TokenTreesReader<'a> { token::CloseDelim(other) => { let mut unclosed_delimiter = None; let mut candidate = None; + if self.last_unclosed_found_span != Some(self.token.span) { // do not complain about the same unclosed delimiter multiple times self.last_unclosed_found_span = Some(self.token.span); @@ -224,12 +238,27 @@ impl<'a> TokenTreesReader<'a> { let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg); - if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { - err.span_label( - span, - "this block is empty, you might have not meant to close it", - ); + // Braces are added at the end, so the last element is the biggest block + if let Some(parent) = self.matching_block_spans.last() { + if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { + // Check if the (empty block) is in the last properly closed block + if (parent.0.to(parent.1)).contains(span) { + err.span_label( + span, + "block is empty, you might have not meant to close it", + ); + } else { + err.span_label(parent.0, "this opening brace..."); + + err.span_label(parent.1, "...matches this closing brace"); + } + } else { + err.span_label(parent.0, "this opening brace..."); + + err.span_label(parent.1, "...matches this closing brace"); + } } + err.span_label(self.token.span, "unexpected closing delimiter"); Err(err) } diff --git a/src/test/ui/parser/issue-70583-block-is-empty-1.rs b/src/test/ui/parser/issue-70583-block-is-empty-1.rs new file mode 100644 index 0000000000000..f560f68f61368 --- /dev/null +++ b/src/test/ui/parser/issue-70583-block-is-empty-1.rs @@ -0,0 +1,20 @@ +pub enum ErrorHandled { + Reported, + TooGeneric, +} + +impl ErrorHandled { + pub fn assert_reported(self) { + match self { + ErrorHandled::Reported => {} + ErrorHandled::TooGeneric => panic!(), + } + } +} + +fn struct_generic(x: Vec) { + for v in x { + println!("{}", v); + } + } +} //~ ERROR unexpected closing delimiter: `}` diff --git a/src/test/ui/parser/issue-70583-block-is-empty-1.stderr b/src/test/ui/parser/issue-70583-block-is-empty-1.stderr new file mode 100644 index 0000000000000..39bf113ef83de --- /dev/null +++ b/src/test/ui/parser/issue-70583-block-is-empty-1.stderr @@ -0,0 +1,13 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-70583-block-is-empty-1.rs:20:1 + | +LL | fn struct_generic(x: Vec) { + | - this opening brace... +... +LL | } + | - ...matches this closing brace +LL | } + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/src/test/ui/parser/issue-70583-block-is-empty-2.rs b/src/test/ui/parser/issue-70583-block-is-empty-2.rs new file mode 100644 index 0000000000000..80f53338a689e --- /dev/null +++ b/src/test/ui/parser/issue-70583-block-is-empty-2.rs @@ -0,0 +1,14 @@ +pub enum ErrorHandled { + Reported, + TooGeneric, +} + +impl ErrorHandled { + pub fn assert_reported(self) { + match self { + ErrorHandled::Reported => {}} + //^~ ERROR block is empty, you might have not meant to close it + ErrorHandled::TooGeneric => panic!(), + } + } +} //~ ERROR unexpected closing delimiter: `}` diff --git a/src/test/ui/parser/issue-70583-block-is-empty-2.stderr b/src/test/ui/parser/issue-70583-block-is-empty-2.stderr new file mode 100644 index 0000000000000..5d37b216427f6 --- /dev/null +++ b/src/test/ui/parser/issue-70583-block-is-empty-2.stderr @@ -0,0 +1,11 @@ +error: unexpected closing delimiter: `}` + --> $DIR/issue-70583-block-is-empty-2.rs:14:1 + | +LL | ErrorHandled::Reported => {}} + | -- block is empty, you might have not meant to close it +... +LL | } + | ^ unexpected closing delimiter + +error: aborting due to previous error + diff --git a/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr b/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr index 042142ac35033..424c7a60c196f 100644 --- a/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr +++ b/src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr @@ -1,6 +1,11 @@ error: unexpected closing delimiter: `}` --> $DIR/macro-mismatched-delim-paren-brace.rs:5:1 | +LL | fn main() { + | - this opening brace... +... +LL | } + | - ...matches this closing brace LL | } | ^ unexpected closing delimiter diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr index f1be5dc5ba7fa..c871e549c9ec3 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -1,6 +1,12 @@ error: unexpected closing delimiter: `}` --> $DIR/mismatched-delim-brace-empty-block.rs:5:1 | +LL | fn main() { + | - this opening brace... +LL | +LL | } + | - ...matches this closing brace +LL | let _ = (); LL | } | ^ unexpected closing delimiter