From 982918f4935fd4677af06d42e0d0b298bfb1c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 00:35:57 +0000 Subject: [PATCH 1/6] Handle str literals written with `'` lexed as lifetime Given `'hello world'` and `'1 str', provide a structured suggestion for a valid string literal: ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:2:26 | LL | println!('hello world'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("hello world"); | ~ ~ ``` ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-1.rs:2:20 | LL | println!('1 + 1'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("1 + 1"); | ~ ~ ``` Fix #119685. --- compiler/rustc_lexer/src/cursor.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 11 +++++ compiler/rustc_parse/src/lexer/mod.rs | 46 +++++++++++++++++-- .../lexer/lex-bad-str-literal-as-char-1.fixed | 6 +++ .../ui/lexer/lex-bad-str-literal-as-char-1.rs | 6 +++ .../lex-bad-str-literal-as-char-1.stderr | 20 ++++++++ .../lexer/lex-bad-str-literal-as-char-2.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-2.rs | 4 ++ .../lex-bad-str-literal-as-char-2.stderr | 13 ++++++ .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 4 ++ .../lex-bad-str-literal-as-char-3.stderr | 14 ++++++ 13 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index aba7f95487e9d..8d8cc9ecc3e9f 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -46,7 +46,7 @@ impl<'a> Cursor<'a> { /// If requested position doesn't exist, `EOF_CHAR` is returned. /// However, getting `EOF_CHAR` doesn't always mean actual end of file, /// it should be checked with `is_eof` method. - pub(crate) fn first(&self) -> char { + pub fn first(&self) -> char { // `.next()` optimizes better than `.nth(0)` self.chars.clone().next().unwrap_or(EOF_CHAR) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index a100e2d47bbbb..888c621f02afd 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -835,6 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string + .suggestion_str = if you meant to write a `str` literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 32b56bb7e877e..140eb6cd18752 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1994,6 +1994,17 @@ pub enum UnknownPrefixSugg { style = "verbose" )] Whitespace(#[primary_span] Span), + #[multipart_suggestion( + parse_suggestion_str, + applicability = "maybe-incorrect", + style = "verbose" + )] + MeantStr { + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f57945a52df37..659e0b63d2ed8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -63,6 +63,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( cursor, override_span, nbsp_is_whitespace: false, + last_lifetime: None, }; let (stream, res, unmatched_delims) = tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); @@ -105,6 +106,10 @@ struct StringReader<'psess, 'src> { /// in this file, it's safe to treat further occurrences of the non-breaking /// space character as whitespace. nbsp_is_whitespace: bool, + + /// Track the `Span` for the leading `'` of the last lifetime. Used for + /// diagnostics to detect possible typo where `"` was meant. + last_lifetime: Option, } impl<'psess, 'src> StringReader<'psess, 'src> { @@ -130,6 +135,18 @@ impl<'psess, 'src> StringReader<'psess, 'src> { debug!("next_token: {:?}({:?})", token.kind, self.str_from(start)); + if let rustc_lexer::TokenKind::Semi + | rustc_lexer::TokenKind::LineComment { .. } + | rustc_lexer::TokenKind::BlockComment { .. } + | rustc_lexer::TokenKind::CloseParen + | rustc_lexer::TokenKind::CloseBrace + | rustc_lexer::TokenKind::CloseBracket = token.kind + { + // Heuristic: we assume that it is unlikely we're dealing with an unterminated + // string surrounded by single quotes. + self.last_lifetime = None; + } + // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs // additional validation. @@ -247,6 +264,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { // expansion purposes. See #12512 for the gory details of why // this is necessary. let lifetime_name = self.str_from(start); + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); self.dcx().struct_err("lifetimes cannot start with a number") @@ -395,10 +413,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.dcx() + let mut err = self + .dcx() .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") - .with_code(E0762) - .emit() + .with_code(E0762); + if let Some(lt_sp) = self.last_lifetime { + err.multipart_suggestion( + "if you meant to write a `str` literal, use double quotes", + vec![ + (lt_sp, "\"".to_string()), + (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + err.emit() } self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' } @@ -673,7 +702,16 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { - Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + if self.cursor.first() == '\'' + && let Some(start) = self.last_lifetime + { + Some(errors::UnknownPrefixSugg::MeantStr { + start, + end: self.mk_sp(self.pos, self.pos + BytePos(1)), + }) + } else { + Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + } } else { None }; diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed new file mode 100644 index 0000000000000..b12139b0b40e9 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!("1 + 1"); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs new file mode 100644 index 0000000000000..6548792f33b4f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!('1 + 1'); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr new file mode 100644 index 0000000000000..675624cfa9415 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -0,0 +1,20 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:20 + | +LL | println!('1 + 1'); + | ^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("1 + 1"); + | ~ ~ + +error: lifetimes cannot start with a number + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14 + | +LL | println!('1 + 1'); + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed new file mode 100644 index 0000000000000..3ccec537c6c34 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(" 1 + 1"); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs new file mode 100644 index 0000000000000..8af72e47dbb4b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(' 1 + 1'); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr new file mode 100644 index 0000000000000..8445d0595f3ed --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -0,0 +1,13 @@ +error: character literal may only contain one codepoint + --> $DIR/lex-bad-str-literal-as-char-2.rs:3:14 + | +LL | println!(' 1 + 1'); + | ^^^^^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!(" 1 + 1"); + | ~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed new file mode 100644 index 0000000000000..3fbe0ea1dabef --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!("hello world"); //~ ERROR unterminated character literal +} 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 new file mode 100644 index 0000000000000..289f3f1d6570f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!('hello world'); //~ ERROR unterminated character literal +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr new file mode 100644 index 0000000000000..ebfbeac02600b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + | +LL | println!('hello world'); + | ^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. From 4a10b01f9504f8ad2ffb9b357845341f4fba6bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 01:07:23 +0000 Subject: [PATCH 2/6] Use shorter span for existing `'` -> `"` structured suggestion --- compiler/rustc_infer/src/errors/mod.rs | 13 +++++------- .../src/infer/error_reporting/mod.rs | 14 ++++--------- compiler/rustc_parse/src/errors.rs | 11 +++++++++- .../src/lexer/unescape_error_reporting.rs | 20 ++++++++++++++----- tests/ui/inference/str-as-char.stderr | 4 ++-- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- .../lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/parser/issues/issue-64732.stderr | 4 ++-- .../parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 14 files changed, 51 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a3cf0d8e5208a..d0b1f2848ff3f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1339,15 +1339,12 @@ pub enum TypeErrorAdditionalDiags { span: Span, code: String, }, - #[suggestion( - infer_meant_str_literal, - code = "\"{code}\"", - applicability = "machine-applicable" - )] + #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")] MeantStrLiteral { - #[primary_span] - span: Span, - code: String, + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, }, #[suggestion( infer_consider_specifying_length, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d2a95593cd25..4b104756b181f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2078,16 +2078,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If a string was expected and the found expression is a character literal, // perhaps the user meant to write `"s"` to specify a string literal. (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { - if let Some(code) = - code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { - span, - code: escape_literal(code), - }) - } - } + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + start: span.with_hi(span.lo() + BytePos(1)), + end: span.with_lo(span.hi() - BytePos(1)), + }) } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 140eb6cd18752..d12818444fc5f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2216,12 +2216,21 @@ pub enum MoreThanOneCharSugg { ch: String, }, #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")] - Quotes { + QuotesFull { #[primary_span] span: Span, is_byte: bool, sugg: String, }, + #[multipart_suggestion(parse_use_double_quotes, applicability = "machine-applicable")] + Quotes { + #[suggestion_part(code = "{prefix}\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + is_byte: bool, + prefix: &'static str, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 3ebad6a9fd73e..1ac6b6fe11566 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,11 +95,21 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - let sugg = format!("{prefix}\"{escaped}\""); - MoreThanOneCharSugg::Quotes { - span: full_lit_span, - is_byte: mode == Mode::Byte, - sugg, + if escaped.len() != lit.len() { + let sugg = format!("{prefix}\"{escaped}\""); + MoreThanOneCharSugg::QuotesFull { + span: full_lit_span, + is_byte: mode == Mode::Byte, + sugg, + } + } else { + MoreThanOneCharSugg::Quotes { + start: full_lit_span + .with_hi(full_lit_span.lo() + BytePos((prefix.len() + 1) as u32)), + end: full_lit_span.with_lo(full_lit_span.hi() - BytePos(1)), + is_byte: mode == Mode::Byte, + prefix, + } } }); dcx.emit_err(UnescapeError::MoreThanOneChar { diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 216f4cda69888..42302435c91bf 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -18,7 +18,7 @@ LL | let _: &str = '\"\"\"'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "\"\"\""; - | ~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/str-as-char.rs:10:19 @@ -42,7 +42,7 @@ LL | let _: &str = 'a'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "a"; - | ~~~ + | ~ ~ error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index 1a91f5e04dbce..bf055a7e31c59 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -18,7 +18,7 @@ LL | let v: Vec(&str) = vec!['1', '2']; help: if you meant to write a `str` literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; - | ~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index 1518a37ab53f3..af64e6efe45ff 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -7,7 +7,7 @@ LL | 'nope' help: if you meant to write a `str` literal, use double quotes | LL | "nope" - | ~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 62a5e424cb469..312b42fc83174 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -7,7 +7,7 @@ LL | static c: char = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "●●"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-3.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "●●"; - | ~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 184817a6579d0..185f460b10def 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -7,7 +7,7 @@ LL | static c: char = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-5.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index 2fe30304a50d6..f49e5a095b34a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -7,7 +7,7 @@ LL | let x: &str = 'ab'; help: if you meant to write a `str` literal, use double quotes | LL | let x: &str = "ab"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:4:19 @@ -18,7 +18,7 @@ LL | let y: char = 'cd'; help: if you meant to write a `str` literal, use double quotes | LL | let y: char = "cd"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:6:13 @@ -29,7 +29,7 @@ LL | let z = 'ef'; help: if you meant to write a `str` literal, use double quotes | LL | let z = "ef"; - | ~~~~ + | ~ ~ error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:13:20 diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 8445d0595f3ed..06b38522ad2dd 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -7,7 +7,7 @@ LL | println!(' 1 + 1'); help: if you meant to write a `str` literal, use double quotes | LL | println!(" 1 + 1"); - | ~~~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8046254937763..8893fa8aae239 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -7,7 +7,7 @@ LL | let _foo = b'hello\0'; help: if you meant to write a byte string literal, use double quotes | LL | let _foo = b"hello\0"; - | ~~~~~~~~~~ + | ~~ ~ error: character literal may only contain one codepoint --> $DIR/issue-64732.rs:6:16 @@ -18,7 +18,7 @@ LL | let _bar = 'hello'; help: if you meant to write a `str` literal, use double quotes | LL | let _bar = "hello"; - | ~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 5cd3bd0fe69d7..1104eaeb8d478 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -12,7 +12,7 @@ LL | let _spade = '♠️'; help: if you meant to write a `str` literal, use double quotes | LL | let _spade = "♠️"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:12:14 @@ -28,7 +28,7 @@ LL | let _s = 'ṩ̂̊'; help: if you meant to write a `str` literal, use double quotes | LL | let _s = "ṩ̂̊"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:17:14 diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 44ec079e92918..03b2309a3171a 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -7,7 +7,7 @@ LL | println!('●●'); help: if you meant to write a `str` literal, use double quotes | LL | println!("●●"); - | ~~~~ + | ~ ~ error: aborting due to 1 previous error From 999a0dc300b7f95eb7d83666514c4ceae76020f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Mar 2024 23:52:04 +0000 Subject: [PATCH 3/6] review comment: `str` -> string in messages --- compiler/rustc_infer/messages.ftl | 2 +- compiler/rustc_parse/messages.ftl | 4 ++-- compiler/rustc_parse/src/lexer/mod.rs | 2 +- tests/ui/inference/str-as-char.stderr | 8 ++++---- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr | 2 +- tests/ui/parser/issues/issue-64732.rs | 2 +- tests/ui/parser/issues/issue-64732.stderr | 2 +- tests/ui/parser/unicode-character-literal.fixed | 4 ++-- tests/ui/parser/unicode-character-literal.rs | 4 ++-- tests/ui/parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 18 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index e44a6ae3b3f2e..521c65c600918 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -169,7 +169,7 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` infer_meant_char_literal = if you meant to write a `char` literal, use single quotes -infer_meant_str_literal = if you meant to write a `str` literal, use double quotes +infer_meant_str_literal = if you meant to write a string literal, use double quotes infer_mismatched_static_lifetime = incompatible lifetime on type infer_more_targeted = {$has_param_name -> [true] `{$param_name}` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 888c621f02afd..7f828c0274361 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -570,7 +570,7 @@ parse_more_than_one_char = character literal may only contain one codepoint .remove_non = consider removing the non-printing characters .use_double_quotes = if you meant to write a {$is_byte -> [true] byte string - *[false] `str` + *[false] string } literal, use double quotes parse_multiple_skipped_lines = multiple lines skipped by escaped newline @@ -835,7 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string - .suggestion_str = if you meant to write a `str` literal, use double quotes + .suggestion_str = if you meant to write a string literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 659e0b63d2ed8..5583e49ba6011 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -419,7 +419,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { .with_code(E0762); if let Some(lt_sp) = self.last_lifetime { err.multipart_suggestion( - "if you meant to write a `str` literal, use double quotes", + "if you meant to write a string literal, use double quotes", vec![ (lt_sp, "\"".to_string()), (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 42302435c91bf..4ca71c5f067fd 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"""'; | ^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~~~~~~~~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '\"\"\"'; | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"\"\"\\"\\"'; | ^^^^^^^^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\\"\\"\\\""; | ~~~~~~~~~~~~~~~~~~~~ @@ -39,7 +39,7 @@ LL | let _: &str = 'a'; | | | expected due to this | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "a"; | ~ ~ diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index bf055a7e31c59..21d383b0e8ce2 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | let v: Vec(&str) = vec!['1', '2']; | ^^^ expected `&str`, found `char` | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index af64e6efe45ff..76cde00404a15 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | 'nope' | ^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | "nope" | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 312b42fc83174..3f339b2ef7d93 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "●●"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "●●"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 185f460b10def..8004157e87f7a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "\x10\x10"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "\x10\x10"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index f49e5a095b34a..96d409d59bb25 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let x: &str = 'ab'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let x: &str = "ab"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let y: char = 'cd'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let y: char = "cd"; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let z = 'ef'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let z = "ef"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr index 675624cfa9415..57c5f82704ec7 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('1 + 1'); | ^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 06b38522ad2dd..f64761af64193 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!(' 1 + 1'); | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!(" 1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr index ebfbeac02600b..262f78569839d 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('hello world'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("hello world"); | ~ ~ diff --git a/tests/ui/parser/issues/issue-64732.rs b/tests/ui/parser/issues/issue-64732.rs index 2db51ea6042aa..ff0f97ea211dc 100644 --- a/tests/ui/parser/issues/issue-64732.rs +++ b/tests/ui/parser/issues/issue-64732.rs @@ -5,5 +5,5 @@ fn main() { //~| HELP if you meant to write a byte string literal, use double quotes let _bar = 'hello'; //~^ ERROR character literal may only contain one codepoint - //~| HELP if you meant to write a `str` literal, use double quotes + //~| HELP if you meant to write a string literal, use double quotes } diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8893fa8aae239..7ec2df6d3bf7e 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _bar = 'hello'; | ^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _bar = "hello"; | ~ ~ diff --git a/tests/ui/parser/unicode-character-literal.fixed b/tests/ui/parser/unicode-character-literal.fixed index 9e31890151cc1..e401ecaf5da77 100644 --- a/tests/ui/parser/unicode-character-literal.fixed +++ b/tests/ui/parser/unicode-character-literal.fixed @@ -7,12 +7,12 @@ fn main() { let _spade = "♠️"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = "ṩ̂̊"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.rs b/tests/ui/parser/unicode-character-literal.rs index d886e5b26a56b..428e4e1ac5a08 100644 --- a/tests/ui/parser/unicode-character-literal.rs +++ b/tests/ui/parser/unicode-character-literal.rs @@ -7,12 +7,12 @@ fn main() { let _spade = '♠️'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = 'ṩ̂̊'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 1104eaeb8d478..726cde2b413e2 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -9,7 +9,7 @@ note: this `♠` is followed by the combining mark `\u{fe0f}` | LL | let _spade = '♠️'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _spade = "♠️"; | ~ ~ @@ -25,7 +25,7 @@ note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` | LL | let _s = 'ṩ̂̊'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _s = "ṩ̂̊"; | ~ ~ diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 03b2309a3171a..0638d371c173b 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!('●●'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("●●"); | ~ ~ From 6f388ef1fb3964fb83bae5c277f9c83bbde4c76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:22:52 +0000 Subject: [PATCH 4/6] Extend test to trigger on 2015, 2018 and 2021 editions --- .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 --- .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 8 ++++-- ...bad-str-literal-as-char-3.rust2015.stderr} | 4 +-- ...-bad-str-literal-as-char-3.rust2018.stderr | 14 ++++++++++ ...-bad-str-literal-as-char-3.rust2021.stderr | 26 +++++++++++++++++++ 5 files changed, 48 insertions(+), 8 deletions(-) delete mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed rename tests/ui/lexer/{lex-bad-str-literal-as-char-3.stderr => lex-bad-str-literal-as-char-3.rust2015.stderr} (79%) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed deleted file mode 100644 index 3fbe0ea1dabef..0000000000000 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed +++ /dev/null @@ -1,4 +0,0 @@ -//@ run-rustfix -fn main() { - println!("hello world"); //~ ERROR unterminated character literal -} 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 289f3f1d6570f..2c0eda97853b0 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 @@ -1,4 +1,8 @@ -//@ run-rustfix +//@ revisions: rust2015 rust2018 rust2021 +//@[rust2018] edition:2018 +//@[rust2021] edition:2021 fn main() { - println!('hello world'); //~ ERROR unterminated character literal + 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.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr similarity index 79% rename from tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr rename to tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr index 262f78569839d..06f127426679f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr @@ -1,8 +1,8 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | LL | println!('hello world'); - | ^^^^ + | ^^^ | help: if you meant to write a string literal, use double quotes | diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr new file mode 100644 index 0000000000000..06f127426679f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. 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 new file mode 100644 index 0000000000000..4170560cfcb04 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -0,0 +1,26 @@ +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 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. From ea1883d7b2207d1a0f08046f11ca493803bc8a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:40:25 +0000 Subject: [PATCH 5/6] Silence redundant error on char literal that was meant to be a string in 2021 edition --- compiler/rustc_lexer/src/cursor.rs | 9 +++++++++ compiler/rustc_parse/src/lexer/mod.rs | 11 ++++++++++- tests/ui/lexer/lex-bad-str-literal-as-char-3.rs | 1 - .../lex-bad-str-literal-as-char-3.rust2021.stderr | 14 +------------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 8d8cc9ecc3e9f..d173c3ac0327b 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -59,6 +59,15 @@ impl<'a> Cursor<'a> { 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 5583e49ba6011..63b2b47630b29 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -698,13 +698,17 @@ impl<'psess, 'src> StringReader<'psess, 'src> { 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 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } 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 2c0eda97853b0..0ae227da5f1e6 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 4170560cfcb04..06f127426679f 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`. From f4d30b156b2958ba01b59a1751e16b5f6e157fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2024 23:46:39 +0000 Subject: [PATCH 6/6] fix rustdoc test --- compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 1ac6b6fe11566..fa242a32a1814 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,7 +95,7 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - if escaped.len() != lit.len() { + if escaped.len() != lit.len() || full_lit_span.is_empty() { let sugg = format!("{prefix}\"{escaped}\""); MoreThanOneCharSugg::QuotesFull { span: full_lit_span,