Skip to content

Commit

Permalink
Auto merge of #58903 - estebank:forgetful-delims, r=petrochenkov
Browse files Browse the repository at this point in the history
Always emit unclosed delimiter diagnostics

Fix #58886.
  • Loading branch information
bors committed Mar 8, 2019
2 parents 0547ceb + 551ea65 commit b58a006
Show file tree
Hide file tree
Showing 18 changed files with 181 additions and 70 deletions.
4 changes: 2 additions & 2 deletions src/librustc_metadata/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,8 @@ impl cstore::CStore {

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

// Mark the attrs as used
let attrs = data.get_item_attrs(id.index, sess);
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/tt/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ pub fn parse(
else if bb_items.is_empty() && next_items.is_empty() {
return Failure(
parser.span,
parser.token,
parser.token.clone(),
"no rules expected this token in macro call",
);
}
Expand Down
11 changes: 9 additions & 2 deletions src/libsyntax/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::source_map::{SourceMap, FilePathMapping};
use crate::feature_gate::UnstableFeatures;
use crate::parse::parser::Parser;
use crate::symbol::Symbol;
use crate::syntax::parse::parser::emit_unclosed_delims;
use crate::tokenstream::{TokenStream, TokenTree};
use crate::diagnostics::plugin::ErrorMap;
use crate::print::pprust::token_to_string;
Expand Down Expand Up @@ -141,8 +142,14 @@ pub fn parse_stream_from_source_str(
source: String,
sess: &ParseSess,
override_span: Option<Span>,
) -> (TokenStream, Vec<lexer::UnmatchedBrace>) {
source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span)
) -> TokenStream {
let (stream, mut errors) = source_file_to_stream(
sess,
sess.source_map().new_source_file(name, source),
override_span,
);
emit_unclosed_delims(&mut errors, &sess.span_diagnostic);
stream
}

/// Creates a new parser from a source string.
Expand Down
43 changes: 34 additions & 9 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use crate::ThinVec;
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
use crate::symbol::{Symbol, keywords};

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

impl<'a> Drop for Parser<'a> {
fn drop(&mut self) {
let diag = self.diagnostic();
emit_unclosed_delims(&mut self.unclosed_delims, diag);
}
}

#[derive(Clone)]
struct TokenCursor {
Expand Down Expand Up @@ -582,6 +589,7 @@ impl<'a> Parser<'a> {
unmatched_angle_bracket_count: 0,
max_angle_bracket_count: 0,
unclosed_delims: Vec::new(),
last_unexpected_token_span: None,
};

let tok = parser.next_tok();
Expand Down Expand Up @@ -775,6 +783,8 @@ impl<'a> Parser<'a> {
} else if inedible.contains(&self.token) {
// leave it in the input
Ok(false)
} else if self.last_unexpected_token_span == Some(self.span) {
FatalError.raise();
} else {
let mut expected = edible.iter()
.map(|x| TokenType::Token(x.clone()))
Expand Down Expand Up @@ -802,6 +812,7 @@ impl<'a> Parser<'a> {
(self.sess.source_map().next_point(self.prev_span),
format!("expected {} here", expect)))
};
self.last_unexpected_token_span = Some(self.span);
let mut err = self.fatal(&msg_exp);
if self.token.is_ident_named("and") {
err.span_suggestion_short(
Expand Down Expand Up @@ -1497,9 +1508,13 @@ impl<'a> Parser<'a> {
pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
maybe_whole!(self, NtTraitItem, |x| x);
let attrs = self.parse_outer_attributes()?;
let mut unclosed_delims = vec![];
let (mut item, tokens) = self.collect_tokens(|this| {
this.parse_trait_item_(at_end, attrs)
let item = this.parse_trait_item_(at_end, attrs);
unclosed_delims.append(&mut this.unclosed_delims);
item
})?;
self.unclosed_delims.append(&mut unclosed_delims);
// See `parse_item` for why this clause is here.
if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
item.tokens = Some(tokens);
Expand Down Expand Up @@ -6333,7 +6348,10 @@ impl<'a> Parser<'a> {
fn_inputs.append(&mut input);
(fn_inputs, recovered)
} else {
return self.unexpected();
match self.expect_one_of(&[], &[]) {
Err(err) => return Err(err),
Ok(recovered) => (vec![self_arg], recovered),
}
}
} else {
self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
Expand Down Expand Up @@ -6459,9 +6477,13 @@ impl<'a> Parser<'a> {
pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
maybe_whole!(self, NtImplItem, |x| x);
let attrs = self.parse_outer_attributes()?;
let mut unclosed_delims = vec![];
let (mut item, tokens) = self.collect_tokens(|this| {
this.parse_impl_item_(at_end, attrs)
let item = this.parse_impl_item_(at_end, attrs);
unclosed_delims.append(&mut this.unclosed_delims);
item
})?;
self.unclosed_delims.append(&mut unclosed_delims);

// See `parse_item` for why this clause is here.
if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
Expand Down Expand Up @@ -7781,9 +7803,13 @@ impl<'a> Parser<'a> {
macros_allowed: bool,
attributes_allowed: bool,
) -> PResult<'a, Option<P<Item>>> {
let mut unclosed_delims = vec![];
let (ret, tokens) = self.collect_tokens(|this| {
this.parse_item_implementation(attrs, macros_allowed, attributes_allowed)
let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed);
unclosed_delims.append(&mut this.unclosed_delims);
item
})?;
self.unclosed_delims.append(&mut unclosed_delims);

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

Expand Down Expand Up @@ -8571,8 +8595,8 @@ impl<'a> Parser<'a> {
}
}

pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors::Handler) {
for unmatched in unclosed_delims {
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, 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_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
Expand All @@ -8586,4 +8610,5 @@ pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors
}
err.emit();
}
unclosed_delims.clear();
}
21 changes: 3 additions & 18 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::print::pprust;
use crate::ptr::P;
use crate::symbol::keywords;
use crate::syntax::parse::parse_stream_from_source_str;
use crate::syntax::parse::parser::emit_unclosed_delims;
use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree};

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

// During early phases of the compiler the AST could get modified
// directly (e.g., attributes added or removed) and the internal cache
Expand Down Expand Up @@ -740,13 +737,7 @@ fn prepend_attrs(sess: &ParseSess,
let source = pprust::attr_to_string(attr);
let macro_filename = FileName::macro_expansion_source_code(&source);
if attr.is_sugared_doc {
let (stream, errors) = parse_stream_from_source_str(
macro_filename,
source,
sess,
Some(span),
);
emit_unclosed_delims(&errors, &sess.span_diagnostic);
let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
builder.push(stream);
continue
}
Expand All @@ -763,13 +754,7 @@ fn prepend_attrs(sess: &ParseSess,
// ... and for more complicated paths, fall back to a reparse hack that
// should eventually be removed.
} else {
let (stream, errors) = parse_stream_from_source_str(
macro_filename,
source,
sess,
Some(span),
);
emit_unclosed_delims(&errors, &sess.span_diagnostic);
let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
brackets.push(stream);
}

Expand Down
7 changes: 2 additions & 5 deletions src/libsyntax_ext/proc_macro_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::parse::lexer::comments;
use syntax::parse::{self, token, ParseSess};
use syntax::parse::parser::emit_unclosed_delims;
use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
use syntax_pos::hygiene::{SyntaxContext, Transparency};
use syntax_pos::symbol::{keywords, Symbol};
Expand Down Expand Up @@ -410,14 +409,12 @@ impl server::TokenStream for Rustc<'_> {
stream.is_empty()
}
fn from_str(&mut self, src: &str) -> Self::TokenStream {
let (tokens, errors) = parse::parse_stream_from_source_str(
parse::parse_stream_from_source_str(
FileName::proc_macro_source_code(src.clone()),
src.to_string(),
self.sess,
Some(self.call_site),
);
emit_unclosed_delims(&errors, &self.sess.span_diagnostic);
tokens
)
}
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
stream.to_string()
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/issues/issue-58856-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
impl A {
fn b(self>
//~^ ERROR expected one of `)`, `,`, or `:`, found `>`
}

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-58856-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: expected one of `)`, `,`, or `:`, found `>`
--> $DIR/issue-58856-1.rs:2:14
|
LL | fn b(self>
| - ^
| | |
| | help: `)` may belong here
| unclosed delimiter

error: aborting due to previous error

14 changes: 14 additions & 0 deletions src/test/ui/issues/issue-58856-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct Empty;

trait Howness {}

impl Howness for () {
fn how_are_you(&self -> Empty {
//~^ ERROR expected one of `)` or `,`, found `->`
//~| ERROR method `how_are_you` is not a member of trait `Howness`
Empty
}
}
//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`,

fn main() {}
30 changes: 30 additions & 0 deletions src/test/ui/issues/issue-58856-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error: expected one of `)` or `,`, found `->`
--> $DIR/issue-58856-2.rs:6:26
|
LL | fn how_are_you(&self -> Empty {
| - -^^
| | |
| | help: `)` may belong here
| unclosed delimiter

error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)`
--> $DIR/issue-58856-2.rs:11:1
|
LL | }
| - expected one of 11 possible tokens here
LL | }
| ^ unexpected token

error[E0407]: method `how_are_you` is not a member of trait `Howness`
--> $DIR/issue-58856-2.rs:6:5
|
LL | / fn how_are_you(&self -> Empty {
LL | | //~^ ERROR expected one of `)` or `,`, found `->`
LL | | //~| ERROR method `how_are_you` is not a member of trait `Howness`
LL | | Empty
LL | | }
| |_____^ not a member of trait `Howness`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0407`.
3 changes: 0 additions & 3 deletions src/test/ui/parser/recover-enum2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ fn main() {
// fail again
enum Test4 {
Nope(i32 {}) //~ ERROR: found `{`
//~^ ERROR: found `{`
}
}
// still recover later
let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
}
14 changes: 1 addition & 13 deletions src/test/ui/parser/recover-enum2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,5 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
LL | Nope(i32 {}) //~ ERROR: found `{`
| ^ expected one of 7 possible tokens here

error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{`
--> $DIR/recover-enum2.rs:27:22
|
LL | Nope(i32 {}) //~ ERROR: found `{`
| ^ expected one of 24 possible tokens here

error: expected expression, found reserved identifier `_`
--> $DIR/recover-enum2.rs:32:22
|
LL | let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_`
| ^ expected expression

error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

6 changes: 6 additions & 0 deletions src/test/ui/parser/unclosed-delimiter-in-dep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mod unclosed_delim_mod;

fn main() {
let _: usize = unclosed_delim_mod::new();
//~^ ERROR mismatched types
}
23 changes: 23 additions & 0 deletions src/test/ui/parser/unclosed-delimiter-in-dep.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error: incorrect close delimiter: `}`
--> $DIR/unclosed_delim_mod.rs:5:1
|
LL | pub fn new() -> Result<Value, ()> {
| - close delimiter possibly meant for this
LL | Ok(Value {
| - un-closed delimiter
LL | }
LL | }
| ^ incorrect close delimiter

error[E0308]: mismatched types
--> $DIR/unclosed-delimiter-in-dep.rs:4:20
|
LL | let _: usize = unclosed_delim_mod::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected usize, found enum `std::result::Result`
|
= note: expected type `usize`
found type `std::result::Result<unclosed_delim_mod::Value, ()>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
6 changes: 6 additions & 0 deletions src/test/ui/parser/unclosed_delim_mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub struct Value {}
pub fn new() -> Result<Value, ()> {
Ok(Value {
}
}
//~^ ERROR incorrect close delimiter
Loading

0 comments on commit b58a006

Please sign in to comment.