about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-01 09:10:23 +0000
committerbors <bors@rust-lang.org>2019-01-01 09:10:23 +0000
commit7a2779a4624db2b9ef1f114a9a9acf9ca5c29d0c (patch)
treed77fec6ca827b9ac39c572ec2d546c5938aa5564
parent0432798fdb4437119b3704cd891b412ba30e5c83 (diff)
parent30961c958da9181a623ea215ed1fd62006f73a85 (diff)
downloadrust-7a2779a4624db2b9ef1f114a9a9acf9ca5c29d0c.tar.gz
rust-7a2779a4624db2b9ef1f114a9a9acf9ca5c29d0c.zip
Auto merge of #57210 - estebank:str-err, r=zackmdavis
Tweak unicode escape diagnostics
-rw-r--r--src/libsyntax/parse/lexer/mod.rs36
-rw-r--r--src/libsyntax_ext/format.rs45
-rw-r--r--src/test/ui/fmt/format-string-error-2.rs15
-rw-r--r--src/test/ui/fmt/format-string-error-2.stderr44
-rw-r--r--src/test/ui/parser/issue-23620-invalid-escapes.rs3
-rw-r--r--src/test/ui/parser/issue-23620-invalid-escapes.stderr16
6 files changed, 148 insertions, 11 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index d13de002968..ecb34e43c59 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -945,12 +945,36 @@ impl<'a> StringReader<'a> {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
                                     let span = self.mk_sp(start, self.pos);
-                                    self.sess.span_diagnostic
-                                        .struct_span_err(span, "incorrect unicode escape sequence")
-                                        .span_help(span,
-                                                   "format of unicode escape sequences is \
-                                                    `\\u{…}`")
-                                        .emit();
+                                    let mut suggestion = "\\u{".to_owned();
+                                    let mut err = self.sess.span_diagnostic.struct_span_err(
+                                        span,
+                                        "incorrect unicode escape sequence",
+                                    );
+                                    let mut i = 0;
+                                    while let (Some(ch), true) = (self.ch, i < 6) {
+                                        if ch.is_digit(16) {
+                                            suggestion.push(ch);
+                                            self.bump();
+                                            i += 1;
+                                        } else {
+                                            break;
+                                        }
+                                    }
+                                    if i != 0 {
+                                        suggestion.push('}');
+                                        err.span_suggestion_with_applicability(
+                                            self.mk_sp(start, self.pos),
+                                            "format of unicode escape sequences uses braces",
+                                            suggestion,
+                                            Applicability::MaybeIncorrect,
+                                        );
+                                    } else {
+                                        err.span_help(
+                                            span,
+                                            "format of unicode escape sequences is `\\u{...}`",
+                                        );
+                                    }
+                                    err.emit();
                                     false
                                 };
                                 if ascii_only {
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index ac1402a0faa..c11f27f3ed5 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -808,12 +808,57 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
                 }
                 ('\\', Some((next_pos, 'n'))) |
                 ('\\', Some((next_pos, 't'))) |
+                ('\\', Some((next_pos, '0'))) |
                 ('\\', Some((next_pos, '\\'))) |
                 ('\\', Some((next_pos, '\''))) |
                 ('\\', Some((next_pos, '\"'))) => {
                     skips.push(*next_pos);
                     let _ = s.next();
                 }
+                ('\\', Some((_, 'x'))) if !is_raw => {
+                    for _ in 0..3 {  // consume `\xAB` literal
+                        if let Some((pos, _)) = s.next() {
+                            skips.push(pos);
+                        } else {
+                            break;
+                        }
+                    }
+                }
+                ('\\', Some((_, 'u'))) if !is_raw => {
+                    if let Some((pos, _)) = s.next() {
+                        skips.push(pos);
+                    }
+                    if let Some((next_pos, next_c)) = s.next() {
+                        if next_c == '{' {
+                            skips.push(next_pos);
+                            let mut i = 0;  // consume up to 6 hexanumeric chars + closing `}`
+                            while let (Some((next_pos, c)), true) = (s.next(), i < 7) {
+                                if c.is_digit(16) {
+                                    skips.push(next_pos);
+                                } else if c == '}' {
+                                    skips.push(next_pos);
+                                    break;
+                                } else {
+                                    break;
+                                }
+                                i += 1;
+                            }
+                        } else if next_c.is_digit(16) {
+                            skips.push(next_pos);
+                            // We suggest adding `{` and `}` when appropriate, accept it here as if
+                            // it were correct
+                            let mut i = 0;  // consume up to 6 hexanumeric chars
+                            while let (Some((next_pos, c)), _) = (s.next(), i < 6) {
+                                if c.is_digit(16) {
+                                    skips.push(next_pos);
+                                } else {
+                                    break;
+                                }
+                                i += 1;
+                            }
+                        }
+                    }
+                }
                 _ if eat_ws => {  // `take_while(|c| c.is_whitespace())`
                     eat_ws = false;
                 }
diff --git a/src/test/ui/fmt/format-string-error-2.rs b/src/test/ui/fmt/format-string-error-2.rs
index 3c6c15c06bb..5c25ae502ff 100644
--- a/src/test/ui/fmt/format-string-error-2.rs
+++ b/src/test/ui/fmt/format-string-error-2.rs
@@ -69,4 +69,19 @@ raw  { \n
     //~^^ ERROR invalid format string
     println!("\t{}");
     //~^ ERROR 1 positional argument in format string
+
+    // note: `\x7B` is `{`
+    println!("\x7B}\u{8} {", 1);
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
+
+    println!("\x7B}\u8 {", 1);
+    //~^ ERROR incorrect unicode escape sequence
+    //~| ERROR argument never used
+
+    // note: raw strings don't escape `\xFF` and `\u{FF}` sequences
+    println!(r#"\x7B}\u{8} {"#, 1);
+    //~^ ERROR invalid format string: unmatched `}` found
+
+    println!(r#"\x7B}\u8 {"#, 1);
+    //~^ ERROR invalid format string: unmatched `}` found
 }
diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr
index face0bc0f5f..baab8529940 100644
--- a/src/test/ui/fmt/format-string-error-2.stderr
+++ b/src/test/ui/fmt/format-string-error-2.stderr
@@ -1,3 +1,11 @@
+error: incorrect unicode escape sequence
+  --> $DIR/format-string-error-2.rs:77:20
+   |
+LL |     println!("/x7B}/u8 {", 1);
+   |                    ^^-
+   |                    |
+   |                    help: format of unicode escape sequences uses braces: `/u{8}`
+
 error: invalid format string: expected `'}'`, found `'a'`
   --> $DIR/format-string-error-2.rs:5:5
    |
@@ -139,5 +147,39 @@ error: 1 positional argument in format string, but no arguments were given
 LL |     println!("/t{}");
    |                 ^^
 
-error: aborting due to 14 previous errors
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/format-string-error-2.rs:74:27
+   |
+LL |     println!("/x7B}/u{8} {", 1);
+   |                          -^ expected `'}'` in format string
+   |                          |
+   |                          because of this opening brace
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: argument never used
+  --> $DIR/format-string-error-2.rs:77:28
+   |
+LL |     println!("/x7B}/u8 {", 1);
+   |              ------------  ^ argument never used
+   |              |
+   |              formatting specifier missing
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/format-string-error-2.rs:82:21
+   |
+LL |     println!(r#"/x7B}/u{8} {"#, 1);
+   |                     ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/format-string-error-2.rs:85:21
+   |
+LL |     println!(r#"/x7B}/u8 {"#, 1);
+   |                     ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+
+error: aborting due to 19 previous errors
 
diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.rs b/src/test/ui/parser/issue-23620-invalid-escapes.rs
index 6895a926b4f..f8a2f1cc7e6 100644
--- a/src/test/ui/parser/issue-23620-invalid-escapes.rs
+++ b/src/test/ui/parser/issue-23620-invalid-escapes.rs
@@ -35,4 +35,7 @@ fn main() {
     //~^ ERROR invalid character in numeric character escape:
     //~^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f]
     //~^^^ ERROR incorrect unicode escape sequence
+
+    let _ = "\u8f";
+    //~^ ERROR incorrect unicode escape sequence
 }
diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.stderr b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
index b1a5764e891..f6e476ab0cd 100644
--- a/src/test/ui/parser/issue-23620-invalid-escapes.stderr
+++ b/src/test/ui/parser/issue-23620-invalid-escapes.stderr
@@ -16,7 +16,7 @@ error: incorrect unicode escape sequence
 LL |     let _ = b'/u';
    |               ^^
    |
-help: format of unicode escape sequences is `/u{…}`
+help: format of unicode escape sequences is `/u{...}`
   --> $DIR/issue-23620-invalid-escapes.rs:10:15
    |
 LL |     let _ = b'/u';
@@ -82,7 +82,7 @@ error: incorrect unicode escape sequence
 LL |     let _ = b"/u{a4a4} /xf /u";
    |                            ^^
    |
-help: format of unicode escape sequences is `/u{…}`
+help: format of unicode escape sequences is `/u{...}`
   --> $DIR/issue-23620-invalid-escapes.rs:28:28
    |
 LL |     let _ = b"/u{a4a4} /xf /u";
@@ -112,11 +112,19 @@ error: incorrect unicode escape sequence
 LL |     let _ = "/xf /u";
    |                  ^^
    |
-help: format of unicode escape sequences is `/u{…}`
+help: format of unicode escape sequences is `/u{...}`
   --> $DIR/issue-23620-invalid-escapes.rs:34:18
    |
 LL |     let _ = "/xf /u";
    |                  ^^
 
-error: aborting due to 17 previous errors
+error: incorrect unicode escape sequence
+  --> $DIR/issue-23620-invalid-escapes.rs:39:14
+   |
+LL |     let _ = "/u8f";
+   |              ^^--
+   |              |
+   |              help: format of unicode escape sequences uses braces: `/u{8f}`
+
+error: aborting due to 18 previous errors