diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 8d8cc9ecc3e..d173c3ac032 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -59,6 +59,15 @@ pub(crate) fn second(&self) -> char { iter.next().unwrap_or(EOF_CHAR) } + /// Peeks the third symbol from the input stream without consuming it. + pub fn third(&self) -> char { + // `.next()` optimizes better than `.nth(1)` + let mut iter = self.chars.clone(); + iter.next(); + iter.next(); + iter.next().unwrap_or(EOF_CHAR) + } + /// Checks if there is nothing more to consume. pub(crate) fn is_eof(&self) -> bool { self.chars.as_str().is_empty() diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5583e49ba60..63b2b47630b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -698,13 +698,17 @@ fn report_unknown_prefix(&self, start: BytePos) { let expn_data = prefix_span.ctxt().outer_expn_data(); if expn_data.edition >= Edition::Edition2021 { + let mut silence = false; // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { if self.cursor.first() == '\'' && let Some(start) = self.last_lifetime + && self.cursor.third() != '\'' { + // An "unclosed `char`" error will be emitted already, silence redundant error. + silence = true; Some(errors::UnknownPrefixSugg::MeantStr { start, end: self.mk_sp(self.pos, self.pos + BytePos(1)), @@ -715,7 +719,12 @@ fn report_unknown_prefix(&self, start: BytePos) { } else { None }; - self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg }); + let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg }; + if silence { + self.dcx().create_err(err).delay_as_bug(); + } else { + self.dcx().emit_err(err); + } } else { // Before Rust 2021, only emit a lint for migration. self.psess.buffer_lint_with_diagnostic( diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 2c0eda97853..0ae227da5f1 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -4,5 +4,4 @@ fn main() { println!('hello world'); //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal - //[rust2021]~^^ ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index 4170560cfcb..06f12742667 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,15 +1,3 @@ -error: prefix `world` is unknown - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 - | -LL | println!('hello world'); - | ^^^^^ unknown prefix - | - = note: prefixed identifiers and literals are reserved since Rust 2021 -help: if you meant to write a string literal, use double quotes - | -LL | println!("hello world"); - | ~ ~ - error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | @@ -21,6 +9,6 @@ help: if you meant to write a string literal, use double quotes LL | println!("hello world"); | ~ ~ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0762`.