about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-10-23 08:14:31 +0200
committerGitHub <noreply@github.com>2022-10-23 08:14:31 +0200
commitb656f5e9a64d6fe0f0b75e76e6350fb08cea562d (patch)
tree649aff2c2c3392d57c0c43afb76d563945fb534c
parent1a077420f864868ec0c8b5d401a4dbb60f18c77d (diff)
parent876248506c9dcb0f4f57db49021374bb0bfc1bd7 (diff)
downloadrust-b656f5e9a64d6fe0f0b75e76e6350fb08cea562d.tar.gz
rust-b656f5e9a64d6fe0f0b75e76e6350fb08cea562d.zip
Rollup merge of #103354 - clubby789:escape-string-literals, r=compiler-errors
Escape string literals when fixing overlong char literal

Fixes #103323

````@rustbot```` label +A-diagnostics +A-suggestion-diagnostics
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs23
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs19
-rw-r--r--src/test/ui/inference/char-as-str-single.fixed1
-rw-r--r--src/test/ui/inference/char-as-str-single.rs1
-rw-r--r--src/test/ui/inference/char-as-str-single.stderr15
-rw-r--r--src/test/ui/inference/str-as-char.fixed4
-rw-r--r--src/test/ui/inference/str-as-char.rs4
-rw-r--r--src/test/ui/inference/str-as-char.stderr24
8 files changed, 83 insertions, 8 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 2fe6f63a9c6..9ff703e521f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2271,6 +2271,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
             }
             FailureCode::Error0308(failure_str) => {
+                fn escape_literal(s: &str) -> String {
+                    let mut escaped = String::with_capacity(s.len());
+                    let mut chrs = s.chars().peekable();
+                    while let Some(first) = chrs.next() {
+                        match (first, chrs.peek()) {
+                            ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+                                escaped.push('\\');
+                                escaped.push(delim);
+                                chrs.next();
+                            }
+                            ('"' | '\'', _) => {
+                                escaped.push('\\');
+                                escaped.push(first)
+                            }
+                            (c, _) => escaped.push(c),
+                        };
+                    }
+                    escaped
+                }
                 let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
                 if let Some((expected, found)) = trace.values.ty() {
                     match (expected.kind(), found.kind()) {
@@ -2292,7 +2311,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 err.span_suggestion(
                                     span,
                                     "if you meant to write a `char` literal, use single quotes",
-                                    format!("'{}'", code),
+                                    format!("'{}'", escape_literal(code)),
                                     Applicability::MachineApplicable,
                                 );
                             }
@@ -2307,7 +2326,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     err.span_suggestion(
                                         span,
                                         "if you meant to write a `str` literal, use double quotes",
-                                        format!("\"{}\"", code),
+                                        format!("\"{}\"", escape_literal(code)),
                                         Applicability::MachineApplicable,
                                     );
                                 }
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 77c4fadab45..f075de71426 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -113,11 +113,26 @@ pub(crate) fn emit_unescape_error(
                 } else {
                     ("", "if you meant to write a `str` literal, use double quotes")
                 };
-
+                let mut escaped = String::with_capacity(lit.len());
+                let mut chrs = lit.chars().peekable();
+                while let Some(first) = chrs.next() {
+                    match (first, chrs.peek()) {
+                        ('\\', Some('"')) => {
+                            escaped.push('\\');
+                            escaped.push('"');
+                            chrs.next();
+                        }
+                        ('"', _) => {
+                            escaped.push('\\');
+                            escaped.push('"')
+                        }
+                        (c, _) => escaped.push(c),
+                    };
+                }
                 handler.span_suggestion(
                     span_with_quotes,
                     msg,
-                    format!("{}\"{}\"", prefix, lit),
+                    format!("{prefix}\"{escaped}\""),
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed
index e401492a830..bab1854dc51 100644
--- a/src/test/ui/inference/char-as-str-single.fixed
+++ b/src/test/ui/inference/char-as-str-single.fixed
@@ -8,4 +8,5 @@
 fn main() {
     let _: char = 'a'; //~ ERROR mismatched types
     let _: char = '人'; //~ ERROR mismatched types
+    let _: char = '\''; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs
index 4f23cea5354..736920643b2 100644
--- a/src/test/ui/inference/char-as-str-single.rs
+++ b/src/test/ui/inference/char-as-str-single.rs
@@ -8,4 +8,5 @@
 fn main() {
     let _: char = "a"; //~ ERROR mismatched types
     let _: char = "人"; //~ ERROR mismatched types
+    let _: char = "'"; //~ ERROR mismatched types
 }
diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr
index 29075c15414..3375ec6ac32 100644
--- a/src/test/ui/inference/char-as-str-single.stderr
+++ b/src/test/ui/inference/char-as-str-single.stderr
@@ -24,6 +24,19 @@ help: if you meant to write a `char` literal, use single quotes
 LL |     let _: char = '人';
    |                   ~~~~
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:11:19
+   |
+LL |     let _: char = "'";
+   |            ----   ^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = '\'';
+   |                   ~~~~
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed
index 09f3dec5a17..6aea809cbdb 100644
--- a/src/test/ui/inference/str-as-char.fixed
+++ b/src/test/ui/inference/str-as-char.fixed
@@ -4,5 +4,7 @@
 // run-rustfix
 
 fn main() {
-    let _: &str = "a"; //~ ERROR mismatched types
+    let _: &str = "a";   //~ ERROR mismatched types
+    let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint
+    let _: &str = "\"\"\""; //~ ERROR character literal may only contain one codepoint
 }
diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs
index 7092a612442..eaa8d788c34 100644
--- a/src/test/ui/inference/str-as-char.rs
+++ b/src/test/ui/inference/str-as-char.rs
@@ -4,5 +4,7 @@
 // run-rustfix
 
 fn main() {
-    let _: &str = 'a'; //~ ERROR mismatched types
+    let _: &str = 'a';   //~ ERROR mismatched types
+    let _: &str = '"""'; //~ ERROR character literal may only contain one codepoint
+    let _: &str = '\"\"\"'; //~ ERROR character literal may only contain one codepoint
 }
diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr
index ebbe7c80f77..2c84dac8e0c 100644
--- a/src/test/ui/inference/str-as-char.stderr
+++ b/src/test/ui/inference/str-as-char.stderr
@@ -1,3 +1,25 @@
+error: character literal may only contain one codepoint
+  --> $DIR/str-as-char.rs:8:19
+   |
+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:9:19
+   |
+LL |     let _: &str = '\"\"\"';
+   |                   ^^^^^^^^
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let _: &str = "\"\"\"";
+   |                   ~~~~~~~~
+
 error[E0308]: mismatched types
   --> $DIR/str-as-char.rs:7:19
    |
@@ -11,6 +33,6 @@ help: if you meant to write a `str` literal, use double quotes
 LL |     let _: &str = "a";
    |                   ~~~
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.