Skip to content

Commit b58a006

Browse files
committedMar 8, 2019
Auto merge of #58903 - estebank:forgetful-delims, r=petrochenkov
Always emit unclosed delimiter diagnostics Fix #58886.
2 parents 0547ceb + 551ea65 commit b58a006

18 files changed

+181
-70
lines changed
 

‎src/librustc_metadata/cstore_impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,8 @@ impl cstore::CStore {
439439

440440
let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);
441441
let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION);
442-
let (body, errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
443-
emit_unclosed_delims(&errors, &sess.diagnostic());
442+
let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None);
443+
emit_unclosed_delims(&mut errors, &sess.diagnostic());
444444

445445
// Mark the attrs as used
446446
let attrs = data.get_item_attrs(id.index, sess);

‎src/libsyntax/ext/tt/macro_parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ pub fn parse(
761761
else if bb_items.is_empty() && next_items.is_empty() {
762762
return Failure(
763763
parser.span,
764-
parser.token,
764+
parser.token.clone(),
765765
"no rules expected this token in macro call",
766766
);
767767
}

‎src/libsyntax/parse/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::source_map::{SourceMap, FilePathMapping};
66
use crate::feature_gate::UnstableFeatures;
77
use crate::parse::parser::Parser;
88
use crate::symbol::Symbol;
9+
use crate::syntax::parse::parser::emit_unclosed_delims;
910
use crate::tokenstream::{TokenStream, TokenTree};
1011
use crate::diagnostics::plugin::ErrorMap;
1112
use crate::print::pprust::token_to_string;
@@ -141,8 +142,14 @@ pub fn parse_stream_from_source_str(
141142
source: String,
142143
sess: &ParseSess,
143144
override_span: Option<Span>,
144-
) -> (TokenStream, Vec<lexer::UnmatchedBrace>) {
145-
source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span)
145+
) -> TokenStream {
146+
let (stream, mut errors) = source_file_to_stream(
147+
sess,
148+
sess.source_map().new_source_file(name, source),
149+
override_span,
150+
);
151+
emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
152+
stream
146153
}
147154

148155
/// Creates a new parser from a source string.

‎src/libsyntax/parse/parser.rs

+34-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::ThinVec;
4646
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
4747
use crate::symbol::{Symbol, keywords};
4848

49-
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
49+
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
5050
use rustc_target::spec::abi::{self, Abi};
5151
use syntax_pos::{Span, MultiSpan, BytePos, FileName};
5252
use log::{debug, trace};
@@ -256,8 +256,15 @@ pub struct Parser<'a> {
256256
/// it gets removed from here. Every entry left at the end gets emitted as an independent
257257
/// error.
258258
crate unclosed_delims: Vec<UnmatchedBrace>,
259+
last_unexpected_token_span: Option<Span>,
259260
}
260261

262+
impl<'a> Drop for Parser<'a> {
263+
fn drop(&mut self) {
264+
let diag = self.diagnostic();
265+
emit_unclosed_delims(&mut self.unclosed_delims, diag);
266+
}
267+
}
261268

262269
#[derive(Clone)]
263270
struct TokenCursor {
@@ -582,6 +589,7 @@ impl<'a> Parser<'a> {
582589
unmatched_angle_bracket_count: 0,
583590
max_angle_bracket_count: 0,
584591
unclosed_delims: Vec::new(),
592+
last_unexpected_token_span: None,
585593
};
586594

587595
let tok = parser.next_tok();
@@ -775,6 +783,8 @@ impl<'a> Parser<'a> {
775783
} else if inedible.contains(&self.token) {
776784
// leave it in the input
777785
Ok(false)
786+
} else if self.last_unexpected_token_span == Some(self.span) {
787+
FatalError.raise();
778788
} else {
779789
let mut expected = edible.iter()
780790
.map(|x| TokenType::Token(x.clone()))
@@ -802,6 +812,7 @@ impl<'a> Parser<'a> {
802812
(self.sess.source_map().next_point(self.prev_span),
803813
format!("expected {} here", expect)))
804814
};
815+
self.last_unexpected_token_span = Some(self.span);
805816
let mut err = self.fatal(&msg_exp);
806817
if self.token.is_ident_named("and") {
807818
err.span_suggestion_short(
@@ -1497,9 +1508,13 @@ impl<'a> Parser<'a> {
14971508
pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
14981509
maybe_whole!(self, NtTraitItem, |x| x);
14991510
let attrs = self.parse_outer_attributes()?;
1511+
let mut unclosed_delims = vec![];
15001512
let (mut item, tokens) = self.collect_tokens(|this| {
1501-
this.parse_trait_item_(at_end, attrs)
1513+
let item = this.parse_trait_item_(at_end, attrs);
1514+
unclosed_delims.append(&mut this.unclosed_delims);
1515+
item
15021516
})?;
1517+
self.unclosed_delims.append(&mut unclosed_delims);
15031518
// See `parse_item` for why this clause is here.
15041519
if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
15051520
item.tokens = Some(tokens);
@@ -6333,7 +6348,10 @@ impl<'a> Parser<'a> {
63336348
fn_inputs.append(&mut input);
63346349
(fn_inputs, recovered)
63356350
} else {
6336-
return self.unexpected();
6351+
match self.expect_one_of(&[], &[]) {
6352+
Err(err) => return Err(err),
6353+
Ok(recovered) => (vec![self_arg], recovered),
6354+
}
63376355
}
63386356
} else {
63396357
self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
@@ -6459,9 +6477,13 @@ impl<'a> Parser<'a> {
64596477
pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
64606478
maybe_whole!(self, NtImplItem, |x| x);
64616479
let attrs = self.parse_outer_attributes()?;
6480+
let mut unclosed_delims = vec![];
64626481
let (mut item, tokens) = self.collect_tokens(|this| {
6463-
this.parse_impl_item_(at_end, attrs)
6482+
let item = this.parse_impl_item_(at_end, attrs);
6483+
unclosed_delims.append(&mut this.unclosed_delims);
6484+
item
64646485
})?;
6486+
self.unclosed_delims.append(&mut unclosed_delims);
64656487

64666488
// See `parse_item` for why this clause is here.
64676489
if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
@@ -7781,9 +7803,13 @@ impl<'a> Parser<'a> {
77817803
macros_allowed: bool,
77827804
attributes_allowed: bool,
77837805
) -> PResult<'a, Option<P<Item>>> {
7806+
let mut unclosed_delims = vec![];
77847807
let (ret, tokens) = self.collect_tokens(|this| {
7785-
this.parse_item_implementation(attrs, macros_allowed, attributes_allowed)
7808+
let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed);
7809+
unclosed_delims.append(&mut this.unclosed_delims);
7810+
item
77867811
})?;
7812+
self.unclosed_delims.append(&mut unclosed_delims);
77877813

77887814
// Once we've parsed an item and recorded the tokens we got while
77897815
// parsing we may want to store `tokens` into the item we're about to
@@ -8539,8 +8565,6 @@ impl<'a> Parser<'a> {
85398565
module: self.parse_mod_items(&token::Eof, lo)?,
85408566
span: lo.to(self.span),
85418567
});
8542-
emit_unclosed_delims(&self.unclosed_delims, self.diagnostic());
8543-
self.unclosed_delims.clear();
85448568
krate
85458569
}
85468570

@@ -8571,8 +8595,8 @@ impl<'a> Parser<'a> {
85718595
}
85728596
}
85738597

8574-
pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors::Handler) {
8575-
for unmatched in unclosed_delims {
8598+
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {
8599+
for unmatched in unclosed_delims.iter() {
85768600
let mut err = handler.struct_span_err(unmatched.found_span, &format!(
85778601
"incorrect close delimiter: `{}`",
85788602
pprust::token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
@@ -8586,4 +8610,5 @@ pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors
85868610
}
85878611
err.emit();
85888612
}
8613+
unclosed_delims.clear();
85898614
}

‎src/libsyntax/parse/token.rs

+3-18
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::print::pprust;
1010
use crate::ptr::P;
1111
use crate::symbol::keywords;
1212
use crate::syntax::parse::parse_stream_from_source_str;
13-
use crate::syntax::parse::parser::emit_unclosed_delims;
1413
use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree};
1514

1615
use syntax_pos::symbol::{self, Symbol};
@@ -675,9 +674,7 @@ impl Nonterminal {
675674
// FIXME(#43081): Avoid this pretty-print + reparse hack
676675
let source = pprust::nonterminal_to_string(self);
677676
let filename = FileName::macro_expansion_source_code(&source);
678-
let (tokens_for_real, errors) =
679-
parse_stream_from_source_str(filename, source, sess, Some(span));
680-
emit_unclosed_delims(&errors, &sess.span_diagnostic);
677+
let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span));
681678

682679
// During early phases of the compiler the AST could get modified
683680
// directly (e.g., attributes added or removed) and the internal cache
@@ -740,13 +737,7 @@ fn prepend_attrs(sess: &ParseSess,
740737
let source = pprust::attr_to_string(attr);
741738
let macro_filename = FileName::macro_expansion_source_code(&source);
742739
if attr.is_sugared_doc {
743-
let (stream, errors) = parse_stream_from_source_str(
744-
macro_filename,
745-
source,
746-
sess,
747-
Some(span),
748-
);
749-
emit_unclosed_delims(&errors, &sess.span_diagnostic);
740+
let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
750741
builder.push(stream);
751742
continue
752743
}
@@ -763,13 +754,7 @@ fn prepend_attrs(sess: &ParseSess,
763754
// ... and for more complicated paths, fall back to a reparse hack that
764755
// should eventually be removed.
765756
} else {
766-
let (stream, errors) = parse_stream_from_source_str(
767-
macro_filename,
768-
source,
769-
sess,
770-
Some(span),
771-
);
772-
emit_unclosed_delims(&errors, &sess.span_diagnostic);
757+
let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
773758
brackets.push(stream);
774759
}
775760

‎src/libsyntax_ext/proc_macro_server.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use syntax::ast;
1212
use syntax::ext::base::ExtCtxt;
1313
use syntax::parse::lexer::comments;
1414
use syntax::parse::{self, token, ParseSess};
15-
use syntax::parse::parser::emit_unclosed_delims;
1615
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
1716
use syntax_pos::hygiene::{SyntaxContext, Transparency};
1817
use syntax_pos::symbol::{keywords, Symbol};
@@ -410,14 +409,12 @@ impl server::TokenStream for Rustc<'_> {
410409
stream.is_empty()
411410
}
412411
fn from_str(&mut self, src: &str) -> Self::TokenStream {
413-
let (tokens, errors) = parse::parse_stream_from_source_str(
412+
parse::parse_stream_from_source_str(
414413
FileName::proc_macro_source_code(src.clone()),
415414
src.to_string(),
416415
self.sess,
417416
Some(self.call_site),
418-
);
419-
emit_unclosed_delims(&errors, &self.sess.span_diagnostic);
420-
tokens
417+
)
421418
}
422419
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
423420
stream.to_string()

‎src/test/ui/issues/issue-58856-1.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
impl A {
2+
fn b(self>
3+
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
4+
}
5+
6+
fn main() {}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: expected one of `)`, `,`, or `:`, found `>`
2+
--> $DIR/issue-58856-1.rs:2:14
3+
|
4+
LL | fn b(self>
5+
| - ^
6+
| | |
7+
| | help: `)` may belong here
8+
| unclosed delimiter
9+
10+
error: aborting due to previous error
11+

‎src/test/ui/issues/issue-58856-2.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct Empty;
2+
3+
trait Howness {}
4+
5+
impl Howness for () {
6+
fn how_are_you(&self -> Empty {
7+
//~^ ERROR expected one of `)` or `,`, found `->`
8+
//~| ERROR method `how_are_you` is not a member of trait `Howness`
9+
Empty
10+
}
11+
}
12+
//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`,
13+
14+
fn main() {}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: expected one of `)` or `,`, found `->`
2+
--> $DIR/issue-58856-2.rs:6:26
3+
|
4+
LL | fn how_are_you(&self -> Empty {
5+
| - -^^
6+
| | |
7+
| | help: `)` may belong here
8+
| unclosed delimiter
9+
10+
error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)`
11+
--> $DIR/issue-58856-2.rs:11:1
12+
|
13+
LL | }
14+
| - expected one of 11 possible tokens here
15+
LL | }
16+
| ^ unexpected token
17+
18+
error[E0407]: method `how_are_you` is not a member of trait `Howness`
19+
--> $DIR/issue-58856-2.rs:6:5
20+
|
21+
LL | / fn how_are_you(&self -> Empty {
22+
LL | | //~^ ERROR expected one of `)` or `,`, found `->`
23+
LL | | //~| ERROR method `how_are_you` is not a member of trait `Howness`
24+
LL | | Empty
25+
LL | | }
26+
| |_____^ not a member of trait `Howness`
27+
28+
error: aborting due to 3 previous errors
29+
30+
For more information about this error, try `rustc --explain E0407`.

‎src/test/ui/parser/recover-enum2.rs

-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ fn main() {
2525
// fail again
2626
enum Test4 {
2727
Nope(i32 {}) //~ ERROR: found `{`
28-
//~^ ERROR: found `{`
2928
}
3029
}
31-
// still recover later
32-
let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
3330
}

‎src/test/ui/parser/recover-enum2.stderr

+1-13
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,5 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
1010
LL | Nope(i32 {}) //~ ERROR: found `{`
1111
| ^ expected one of 7 possible tokens here
1212

13-
error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{`
14-
--> $DIR/recover-enum2.rs:27:22
15-
|
16-
LL | Nope(i32 {}) //~ ERROR: found `{`
17-
| ^ expected one of 24 possible tokens here
18-
19-
error: expected expression, found reserved identifier `_`
20-
--> $DIR/recover-enum2.rs:32:22
21-
|
22-
LL | let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
23-
| ^ expected expression
24-
25-
error: aborting due to 4 previous errors
13+
error: aborting due to 2 previous errors
2614

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod unclosed_delim_mod;
2+
3+
fn main() {
4+
let _: usize = unclosed_delim_mod::new();
5+
//~^ ERROR mismatched types
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: incorrect close delimiter: `}`
2+
--> $DIR/unclosed_delim_mod.rs:5:1
3+
|
4+
LL | pub fn new() -> Result<Value, ()> {
5+
| - close delimiter possibly meant for this
6+
LL | Ok(Value {
7+
| - un-closed delimiter
8+
LL | }
9+
LL | }
10+
| ^ incorrect close delimiter
11+
12+
error[E0308]: mismatched types
13+
--> $DIR/unclosed-delimiter-in-dep.rs:4:20
14+
|
15+
LL | let _: usize = unclosed_delim_mod::new();
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected usize, found enum `std::result::Result`
17+
|
18+
= note: expected type `usize`
19+
found type `std::result::Result<unclosed_delim_mod::Value, ()>`
20+
21+
error: aborting due to 2 previous errors
22+
23+
For more information about this error, try `rustc --explain E0308`.
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pub struct Value {}
2+
pub fn new() -> Result<Value, ()> {
3+
Ok(Value {
4+
}
5+
}
6+
//~^ ERROR incorrect close delimiter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: incorrect close delimiter: `}`
2+
--> $DIR/unclosed_delim_mod.rs:5:1
3+
|
4+
LL | pub fn new() -> Result<Value, ()> {
5+
| - close delimiter possibly meant for this
6+
LL | Ok(Value {
7+
| - un-closed delimiter
8+
LL | }
9+
LL | }
10+
| ^ incorrect close delimiter
11+
12+
error[E0601]: `main` function not found in crate `unclosed_delim_mod`
13+
|
14+
= note: consider adding a `main` function to `$DIR/unclosed_delim_mod.rs`
15+
16+
error: aborting due to 2 previous errors
17+
18+
For more information about this error, try `rustc --explain E0601`.

‎src/test/ui/resolve/token-error-correct-3.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ pub mod raw {
1010
pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
1111
callback: F)
1212
-> io::Result<bool> {
13-
if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory`
14-
callback(path.as_ref(); //~ ERROR expected one of
15-
fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
16-
//~^ expected (), found enum `std::result::Result`
17-
//~| expected type `()`
18-
//~| found type `std::result::Result<bool, std::io::Error>`
19-
//~| expected one of
13+
if !is_directory(path.as_ref()) {
14+
//~^ ERROR cannot find function `is_directory`
15+
callback(path.as_ref();
16+
//~^ ERROR expected one of
17+
fs::create_dir_all(path.as_ref()).map(|()| true)
18+
//~^ ERROR mismatched types
2019
} else {
21-
//~^ ERROR: expected one of
22-
//~| unexpected token
20+
//~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
2321
Ok(false);
2422
}
2523

‎src/test/ui/resolve/token-error-correct-3.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
2-
--> $DIR/token-error-correct-3.rs:14:35
2+
--> $DIR/token-error-correct-3.rs:15:35
33
|
4-
LL | callback(path.as_ref(); //~ ERROR expected one of
4+
LL | callback(path.as_ref();
55
| - ^
66
| | |
77
| | help: `)` may belong here
88
| unclosed delimiter
99

1010
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
11-
--> $DIR/token-error-correct-3.rs:20:9
11+
--> $DIR/token-error-correct-3.rs:19:9
1212
|
13-
LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
13+
LL | fs::create_dir_all(path.as_ref()).map(|()| true)
1414
| - expected one of `.`, `;`, `?`, `}`, or an operator here
15-
...
15+
LL | //~^ ERROR mismatched types
1616
LL | } else {
1717
| ^ unexpected token
1818

1919
error[E0425]: cannot find function `is_directory` in this scope
2020
--> $DIR/token-error-correct-3.rs:13:13
2121
|
22-
LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory`
22+
LL | if !is_directory(path.as_ref()) {
2323
| ^^^^^^^^^^^^ not found in this scope
2424

2525
error[E0308]: mismatched types
26-
--> $DIR/token-error-correct-3.rs:15:13
26+
--> $DIR/token-error-correct-3.rs:17:13
2727
|
28-
LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
28+
LL | fs::create_dir_all(path.as_ref()).map(|()| true)
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
3030
| |
3131
| expected (), found enum `std::result::Result`

0 commit comments

Comments
 (0)
Please sign in to comment.