Skip to content

Tweak unicode escape diagnostics #57210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions src/libsyntax/parse/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
45 changes: 45 additions & 0 deletions src/libsyntax_ext/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/fmt/format-string-error-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
44 changes: 43 additions & 1 deletion src/test/ui/fmt/format-string-error-2.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
error: incorrect unicode escape sequence
--> $DIR/format-string-error-2.rs:77:20
|
LL | println!("/x7B}/u8 {", 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait ... the .rs file source line said println!("\x7B}\u8 {", 1); (with backslashes), why are there forward slashes in the output here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zackmdavis can't find the PR, but UI tests normalize backslashes to forward slashes for Windows' sake to avoid further differences across platforms when running tests. It always makes me recoil for a second until I remember that that's a thing.

| ^^-
| |
| 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
|
Expand Down Expand Up @@ -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

3 changes: 3 additions & 0 deletions src/test/ui/parser/issue-23620-invalid-escapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
16 changes: 12 additions & 4 deletions src/test/ui/parser/issue-23620-invalid-escapes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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