diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 0c9c9adcf9da6..5cc8324b31606 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -363,7 +363,8 @@ impl<'a> HashStable> for token::TokenKind { } token::DocComment(val) | - token::Shebang(val) => val.hash_stable(hcx, hasher), + token::Shebang(val) | + token::Unknown(val) => val.hash_stable(hcx, hasher), } } } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index fb9919d777db1..c0071906b31b2 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -3,7 +3,7 @@ use rustc::session::Session; use crate::generated_code; use syntax::parse::lexer::{self, StringReader}; -use syntax::parse::token::{self, TokenKind}; +use syntax::parse::token::TokenKind; use syntax_pos::*; #[derive(Clone)] @@ -51,16 +51,9 @@ impl<'a> SpanUtils<'a> { } pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option { - let mut toks = self.retokenise_span(span); - loop { - let next = toks.next_token(); - if next == token::Eof { - return None; - } - if next == tok { - return Some(next.span); - } - } + let token = self.retokenise_span(span) + .find(|it| it.kind == tok)?; + Some(token.span) } // // Return the name for a macro definition (identifier after first `!`) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 8132074d6e0e7..5d86ee9721b75 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -44,7 +44,7 @@ pub fn render_with_highlighting( let mut highlighted_source = vec![]; if classifier.write_source(&mut highlighted_source).is_err() { - Err(classifier.lexer.buffer_fatal_errors()) + Err(()) } else { Ok(String::from_utf8_lossy(&highlighted_source).into_owned()) } @@ -59,14 +59,9 @@ pub fn render_with_highlighting( } write_footer(&mut out).unwrap(); } - Err(errors) => { - // If errors are encountered while trying to highlight, cancel the errors and just emit - // the unhighlighted source. The errors will have already been reported in the - // `check-code-block-syntax` pass. - for mut error in errors { - error.cancel(); - } - + Err(()) => { + // If errors are encountered while trying to highlight, just emit + // the unhighlighted source. write!(out, "
{}
", src).unwrap(); } } @@ -192,14 +187,20 @@ impl<'a> Classifier<'a> { if let Some(token) = self.peek_token.take() { return Ok(token); } - self.lexer.try_next_token().map_err(|()| HighlightError::LexError) + let token = self.lexer.next_token(); + if let token::Unknown(..) = &token.kind { + return Err(HighlightError::LexError); + } + Ok(token) } fn peek(&mut self) -> Result<&Token, HighlightError> { if self.peek_token.is_none() { - self.peek_token = Some( - self.lexer.try_next_token().map_err(|()| HighlightError::LexError)? - ); + let token = self.lexer.next_token(); + if let token::Unknown(..) = &token.kind { + return Err(HighlightError::LexError); + } + self.peek_token = Some(token); } Ok(self.peek_token.as_ref().unwrap()) } @@ -237,7 +238,7 @@ impl<'a> Classifier<'a> { return Ok(()); }, - token::Whitespace => Class::None, + token::Whitespace | token::Unknown(..) => Class::None, token::Comment => Class::Comment, token::DocComment(..) => Class::DocComment, diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 0488153e7cb73..357e17d2d1bc4 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -32,24 +32,20 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { dox[code_block.code].to_owned(), ); - let errors = { + let has_errors = { + let mut has_errors = false; let mut lexer = Lexer::new(&sess, source_file, None); - while let Ok(token::Token { kind, .. }) = lexer.try_next_token() { - if kind == token::Eof { - break; + loop { + match lexer.next_token().kind { + token::Eof => break, + token::Unknown(..) => has_errors = true, + _ => (), } } - - let errors = lexer.buffer_fatal_errors(); - - if !errors.is_empty() { - Err(errors) - } else { - Ok(()) - } + has_errors }; - if let Err(errors) = errors { + if has_errors { let mut diag = if let Some(sp) = super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) { @@ -58,11 +54,6 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { .sess() .struct_span_warn(sp, "could not parse code block as Rust code"); - for mut err in errors { - diag.note(&format!("error from rustc: {}", err.message())); - err.cancel(); - } - if code_block.syntax.is_none() && code_block.is_fenced { let sp = sp.from_inner(InnerSpan::new(0, 3)); diag.span_suggestion( @@ -82,11 +73,6 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { "doc comment contains an invalid Rust code block", ); - for mut err in errors { - // Don't bother reporting the error, because we can't show where it happened. - err.cancel(); - } - if code_block.syntax.is_none() && code_block.is_fenced { diag.help("mark blocks that do not contain Rust code as text: ```text"); } diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 8d0023c9ab1eb..36621ce777510 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -184,7 +184,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> } OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Eof => unreachable!(), + Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => unreachable!(), } } } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 950b1b2ff5340..f162b129f7187 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -3,7 +3,7 @@ use crate::parse::token::{self, Token, TokenKind}; use crate::symbol::{sym, Symbol}; use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; -use errors::{FatalError, Diagnostic, DiagnosticBuilder}; +use errors::{FatalError, DiagnosticBuilder}; use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION}; use rustc_lexer::Base; use rustc_lexer::unescape; @@ -39,7 +39,6 @@ pub struct StringReader<'a> { pos: BytePos, /// Stop reading src at this index. end_src_index: usize, - fatal_errs: Vec>, /// Source text to tokenize. src: Lrc, override_span: Option, @@ -62,7 +61,6 @@ impl<'a> StringReader<'a> { pos: source_file.start_pos, end_src_index: src.len(), src, - fatal_errs: Vec::new(), override_span, } } @@ -89,91 +87,6 @@ impl<'a> StringReader<'a> { self.override_span.unwrap_or_else(|| Span::new(lo, hi, NO_EXPANSION)) } - fn unwrap_or_abort(&mut self, res: Result) -> Token { - match res { - Ok(tok) => tok, - Err(_) => { - self.emit_fatal_errors(); - FatalError.raise(); - } - } - } - - /// Returns the next token, including trivia like whitespace or comments. - /// - /// `Err(())` means that some errors were encountered, which can be - /// retrieved using `buffer_fatal_errors`. - pub fn try_next_token(&mut self) -> Result { - assert!(self.fatal_errs.is_empty()); - - let start_src_index = self.src_index(self.pos); - let text: &str = &self.src[start_src_index..self.end_src_index]; - - if text.is_empty() { - let span = self.mk_sp(self.pos, self.pos); - return Ok(Token::new(token::Eof, span)); - } - - { - let is_beginning_of_file = self.pos == self.start_pos; - if is_beginning_of_file { - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(shebang_len); - - let sym = self.symbol_from(start + BytePos::from_usize("#!".len())); - let kind = token::Shebang(sym); - - let span = self.mk_sp(start, self.pos); - return Ok(Token::new(kind, span)); - } - } - } - - let token = rustc_lexer::first_token(text); - - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(token.len); - - debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); - - // This could use `?`, but that makes code significantly (10-20%) slower. - // https://github.com/rust-lang/rust/issues/37939 - let kind = match self.cook_lexer_token(token.kind, start) { - Ok(it) => it, - Err(err) => return Err(self.fatal_errs.push(err)), - }; - - let span = self.mk_sp(start, self.pos); - Ok(Token::new(kind, span)) - } - - /// Returns the next token, including trivia like whitespace or comments. - /// - /// Aborts in case of an error. - pub fn next_token(&mut self) -> Token { - let res = self.try_next_token(); - self.unwrap_or_abort(res) - } - - fn emit_fatal_errors(&mut self) { - for err in &mut self.fatal_errs { - err.emit(); - } - - self.fatal_errs.clear(); - } - - pub fn buffer_fatal_errors(&mut self) -> Vec { - let mut buffer = Vec::new(); - - for err in self.fatal_errs.drain(..) { - err.buffer(&mut buffer); - } - - buffer - } - /// Report a fatal lexical error with a given span. fn fatal_span(&self, sp: Span, m: &str) -> FatalError { self.sess.span_diagnostic.span_fatal(sp, m) @@ -218,8 +131,8 @@ impl<'a> StringReader<'a> { &self, token: rustc_lexer::TokenKind, start: BytePos, - ) -> Result> { - let kind = match token { + ) -> TokenKind { + match token { rustc_lexer::TokenKind::LineComment => { let string = self.str_from(start); // comments with only more "/"s are not doc comments @@ -396,16 +309,12 @@ impl<'a> StringReader<'a> { // this should be inside `rustc_lexer`. However, we should first remove compound // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it, // as there will be less overall work to do this way. - return match unicode_chars::check_for_substitution(self, start, c, &mut err) { - Some(token) => { - err.emit(); - Ok(token) - } - None => Err(err), - } + let token = unicode_chars::check_for_substitution(self, start, c, &mut err) + .unwrap_or_else(|| token::Unknown(self.symbol_from(start))); + err.emit(); + token } - }; - Ok(kind) + } } fn cook_lexer_literal( @@ -766,6 +675,50 @@ impl<'a> StringReader<'a> { } } +impl Iterator for StringReader<'_> { + type Item = Token; + + /// Returns the next token, including trivia like whitespace or comments. + fn next(&mut self) -> Option { + let start_src_index = self.src_index(self.pos); + let text: &str = &self.src[start_src_index..self.end_src_index]; + + if text.is_empty() { + return None; + } + + { + let is_beginning_of_file = self.pos == self.start_pos; + if is_beginning_of_file { + if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(shebang_len); + + let sym = self.symbol_from(start + BytePos::from_usize("#!".len())); + let kind = token::Shebang(sym); + + let span = self.mk_sp(start, self.pos); + return Some(Token::new(kind, span)); + } + } + } + + let token = rustc_lexer::first_token(text); + + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(token.len); + + debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); + + // This could use `?`, but that makes code significantly (10-20%) slower. + // https://github.com/rust-lang/rust/issues/37939 + let kind = self.cook_lexer_token(token.kind, start); + + let span = self.mk_sp(start, self.pos); + Some(Token::new(kind, span)) + } +} + fn is_doc_comment(s: &str) -> bool { let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/') || s.starts_with("//!"); diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 830fbec58ded9..5c8050ab1e3c4 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -10,7 +10,7 @@ impl<'a> StringReader<'a> { crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { string_reader: self, - token: Token::dummy(), + token: None, joint_to_prev: Joint, open_braces: Vec::new(), unmatched_braces: Vec::new(), @@ -24,7 +24,7 @@ impl<'a> StringReader<'a> { struct TokenTreesReader<'a> { string_reader: StringReader<'a>, - token: Token, + token: Option, joint_to_prev: IsJoint, /// Stack of open delimiters and their spans. Used for error message. open_braces: Vec<(token::DelimToken, Span)>, @@ -42,7 +42,7 @@ impl<'a> TokenTreesReader<'a> { let mut tts = Vec::new(); self.real_token(); - while self.token != token::Eof { + while self.token.is_some() { tts.push(self.parse_token_tree()?); } @@ -53,7 +53,7 @@ impl<'a> TokenTreesReader<'a> { fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { let mut tts = vec![]; loop { - if let token::CloseDelim(..) = self.token.kind { + if let Some( Token { kind: token::CloseDelim(..), .. }) = self.token { return TokenStream::new(tts); } @@ -69,11 +69,12 @@ 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 => { + match self.token { + None => { let msg = "this file contains an un-closed delimiter"; + let span = self.string_reader.mk_sp(self.string_reader.pos, self.string_reader.pos); let mut err = self.string_reader.sess.span_diagnostic - .struct_span_err(self.token.span, msg); + .struct_span_err(span, msg); for &(_, sp) in &self.open_braces { err.span_label(sp, "un-closed delimiter"); } @@ -101,12 +102,9 @@ impl<'a> TokenTreesReader<'a> { } Err(err) }, - token::OpenDelim(delim) => { - // The span for beginning of the delimited section - let pre_span = self.token.span; - + Some(Token { kind: token::OpenDelim(delim), span: pre_span }) => { // Parse the open delimiter. - self.open_braces.push((delim, self.token.span)); + self.open_braces.push((delim, pre_span)); self.real_token(); // Parse the token trees within the delimiters. @@ -115,11 +113,15 @@ impl<'a> TokenTreesReader<'a> { let tts = self.parse_token_trees_until_close_delim(); // Expand to cover the entire delimited token tree - let delim_span = DelimSpan::from_pair(pre_span, self.token.span); + let post_pan = self.token.as_ref().map_or_else( + || self.string_reader.mk_sp(self.string_reader.pos, self.string_reader.pos), + |it| it.span, + ); + let delim_span = DelimSpan::from_pair(pre_span, post_pan); - match self.token.kind { + match self.token { // Correct delimiter. - token::CloseDelim(d) if d == delim => { + Some(Token { kind: token::CloseDelim(d), span }) if d == delim => { let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); if self.open_braces.len() == 0 { // Clear up these spans to avoid suggesting them as we've found @@ -127,26 +129,26 @@ impl<'a> TokenTreesReader<'a> { self.matching_delim_spans.clear(); } else { self.matching_delim_spans.push( - (open_brace, open_brace_span, self.token.span), + (open_brace, open_brace_span, span), ); } // Parse the close delimiter. self.real_token(); } // Incorrect delimiter. - token::CloseDelim(other) => { + Some(Token { kind: token::CloseDelim(other), span }) => { let mut unclosed_delimiter = None; let mut candidate = None; - if self.last_unclosed_found_span != Some(self.token.span) { + if self.last_unclosed_found_span != Some(span) { // do not complain about the same unclosed delimiter multiple times - self.last_unclosed_found_span = Some(self.token.span); + self.last_unclosed_found_span = Some(span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be // closed! The parser just hasn't gotten to them yet. if let Some(&(_, sp)) = self.open_braces.last() { unclosed_delimiter = Some(sp); }; - if let Some(current_padding) = sm.span_to_margin(self.token.span) { + if let Some(current_padding) = sm.span_to_margin(span) { for (brace, brace_span) in &self.open_braces { if let Some(padding) = sm.span_to_margin(*brace_span) { // high likelihood of these two corresponding @@ -160,7 +162,7 @@ impl<'a> TokenTreesReader<'a> { self.unmatched_braces.push(UnmatchedBrace { expected_delim: tok, found_delim: other, - found_span: self.token.span, + found_span: span, unclosed_span: unclosed_delimiter, candidate_span: candidate, }); @@ -179,12 +181,12 @@ impl<'a> TokenTreesReader<'a> { self.real_token(); } } - token::Eof => { + Some(_) => {} + None => { // Silently recover, the EOF token will be seen again // and an error emitted then. Thus we don't pop from // self.open_braces here. }, - _ => {} } Ok(TokenTree::Delimited( @@ -193,20 +195,21 @@ impl<'a> TokenTreesReader<'a> { tts.into() ).into()) }, - token::CloseDelim(_) => { + Some(Token { kind: token::CloseDelim(_), span }) => { // An unexpected closing delimiter (i.e., there is no // matching opening delimiter). - let token_str = token_to_string(&self.token); + let token_str = self.token.as_ref().map(token_to_string).unwrap_or("".into()); let msg = format!("unexpected close delimiter: `{}`", token_str); let mut err = self.string_reader.sess.span_diagnostic - .struct_span_err(self.token.span, &msg); - err.span_label(self.token.span, "unexpected close delimiter"); + .struct_span_err(span, &msg); + err.span_label(span, "unexpected close delimiter"); Err(err) }, - _ => { - let tt = TokenTree::Token(self.token.take()); + Some(_) => { + let tt = TokenTree::Token(self.token.take().unwrap()); self.real_token(); - let is_joint = self.joint_to_prev == Joint && self.token.is_op(); + let is_joint = self.joint_to_prev == Joint + && self.token.as_ref().map(|it| it.is_op()) == Some(true); Ok((tt, if is_joint { Joint } else { NonJoint })) } } @@ -215,16 +218,17 @@ impl<'a> TokenTreesReader<'a> { fn real_token(&mut self) { self.joint_to_prev = Joint; loop { - let token = self.string_reader.next_token(); - match token.kind { - token::Whitespace | token::Comment | token::Shebang(_) => { - self.joint_to_prev = NonJoint; + self.token = self.string_reader.next(); + if let Some(token) = &self.token { + match token.kind { + token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => { + self.joint_to_prev = NonJoint; + continue; + } + _ => (), } - _ => { - self.token = token; - return; - }, } + break; } } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 73adb5c947c0b..be800b4de66af 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -255,6 +255,8 @@ pub enum TokenKind { /// A comment. Comment, Shebang(ast::Name), + /// A completely invalid token which should be skipped. + Unknown(ast::Name), Eof, } @@ -603,7 +605,7 @@ impl Token { DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | - Whitespace | Comment | Shebang(..) | Eof => return None, + Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => return None, }; Some(Token::new(kind, self.span.to(joint.span))) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2ef8a919b9c56..378ba1e4107a4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -288,6 +288,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::Whitespace => " ".to_string(), token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s), + token::Unknown(s) => s.to_string(), token::Interpolated(ref nt) => nonterminal_to_string(nt), } diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index b4ed747b44c81..3bebbecb9dfcf 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -1,3 +1,21 @@ +error: unknown start of token: \ + --> :1:1 + | +1 | \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ + | ^ + +error: unknown start of token: \ + --> :1:43 + | +1 | \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ + | ^ + +error: unknown start of token: \ + --> :1:60 + | +1 | \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ + | ^ + warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:3:5 | @@ -6,13 +24,31 @@ LL | /// ``` LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ LL | | /// ``` | |_______^ - | - = note: error from rustc: unknown start of token: \ help: mark blocks that do not contain Rust code as text | LL | /// ```text | ^^^^^^^ +error: unknown start of token: ` + --> :3:30 + | +3 | | ^^^^^^ did you mean `baz::foobar`? + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +3 | | ^^^^^^ did you mean 'baz::foobar`? + | ^ + +error: unknown start of token: ` + --> :3:42 + | +3 | | ^^^^^^ did you mean `baz::foobar`? + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +3 | | ^^^^^^ did you mean `baz::foobar'? + | ^ + warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:8:5 | @@ -23,13 +59,17 @@ LL | | /// LL | use foobar::Baz; LL | | /// | ^^^^^^ did you mean `baz::foobar`? LL | | /// ``` | |_______^ - | - = note: error from rustc: unknown start of token: ` help: mark blocks that do not contain Rust code as text | LL | /// ```text | ^^^^^^^ +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:19:5 | @@ -38,13 +78,17 @@ LL | /// ``` LL | | /// \_ LL | | /// ``` | |_______^ - | - = note: error from rustc: unknown start of token: \ help: mark blocks that do not contain Rust code as text | LL | /// ```text | ^^^^^^^ +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:32:5 | @@ -53,8 +97,12 @@ LL | /// ```rust LL | | /// \_ LL | | /// ``` | |_______^ - | - = note: error from rustc: unknown start of token: \ + +error: unknown start of token: \ + --> :2:5 + | +2 | \_ + | ^ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:41:9 @@ -63,16 +111,48 @@ LL | /// code with bad syntax | _________^ LL | | /// \_ | |__________^ - | - = note: error from rustc: unknown start of token: \ + +error: unknown start of token: ` + --> :1:1 + | +1 | ``` + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +1 | '`` + | ^ + +error: unknown start of token: ` + --> :1:2 + | +1 | ``` + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +1 | `'` + | ^ + +error: unknown start of token: ` + --> :1:3 + | +1 | ``` + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +1 | ``' + | ^ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:55:9 | LL | /// ``` | ^^^ - | - = note: error from rustc: unknown start of token: ` + +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:58:5 @@ -82,8 +162,12 @@ LL | /// ```edition2018 LL | | /// \_ LL | | /// ``` | |_______^ - | - = note: error from rustc: unknown start of token: \ + +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ warning: doc comment contains an invalid Rust code block --> $DIR/invalid-syntax.rs:63:1 @@ -95,3 +179,59 @@ LL | | #[doc = "```"] | = help: mark blocks that do not contain Rust code as text: ```text +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + +error: unknown start of token: ` + --> :1:1 + | +1 | ``` + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +1 | '`` + | ^ + +error: unknown start of token: \ + --> :2:1 + | +2 | \_ + | ^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \_ + | ^ + +error: unknown start of token: ` + --> :3:30 + | +3 | | ^^^^^^ did you mean `baz::foobar`? + | ^ +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +3 | | ^^^^^^ did you mean 'baz::foobar`? + | ^ + +error: unknown start of token: \ + --> :1:1 + | +1 | \__________pkt->size___________/ \_result->size_/ \__pkt->size__/ + | ^ + diff --git a/src/test/ui/parser/lex-bad-token.rs b/src/test/ui/parser/lex-bad-token.rs index feb670c3d3dd0..9e4824611128d 100644 --- a/src/test/ui/parser/lex-bad-token.rs +++ b/src/test/ui/parser/lex-bad-token.rs @@ -1 +1,3 @@ ● //~ ERROR: unknown start of token + +fn main() {} diff --git a/src/test/ui/parser/lex-stray-backslash.rs b/src/test/ui/parser/lex-stray-backslash.rs index 90d359231a6e7..bb27f44c279f7 100644 --- a/src/test/ui/parser/lex-stray-backslash.rs +++ b/src/test/ui/parser/lex-stray-backslash.rs @@ -1 +1,3 @@ \ //~ ERROR: unknown start of token: \ + +fn main() {} diff --git a/src/test/ui/parser/unicode-quote-chars.rs b/src/test/ui/parser/unicode-quote-chars.rs index 69644211b8a11..1812dad81afc3 100644 --- a/src/test/ui/parser/unicode-quote-chars.rs +++ b/src/test/ui/parser/unicode-quote-chars.rs @@ -4,4 +4,7 @@ fn main() { println!(“hello world”); //~^ ERROR unknown start of token: \u{201c} //~^^ HELP Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '"' (Quotation Mark), but are not + //~^^^ ERROR unknown start of token: \u{201d} + //~^^^^ HELP Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quotation Mark), but it is not + //~^^^^^ ERROR expected token: `,` } diff --git a/src/test/ui/parser/unicode-quote-chars.stderr b/src/test/ui/parser/unicode-quote-chars.stderr index 4a09ed75605e4..84e45ecd873a4 100644 --- a/src/test/ui/parser/unicode-quote-chars.stderr +++ b/src/test/ui/parser/unicode-quote-chars.stderr @@ -8,5 +8,21 @@ help: Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Dou LL | println!("hello world"); | ^^^^^^^^^^^^^ -error: aborting due to previous error +error: unknown start of token: \u{201d} + --> $DIR/unicode-quote-chars.rs:4:26 + | +LL | println!(“hello world”); + | ^ +help: Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quotation Mark), but it is not + | +LL | println!(“hello world"); + | ^ + +error: expected token: `,` + --> $DIR/unicode-quote-chars.rs:4:21 + | +LL | println!(“hello world”); + | ^^^^^ expected `,` + +error: aborting due to 3 previous errors