Skip to content

Commit 7a2779a

Browse files
committed
Auto merge of #57210 - estebank:str-err, r=zackmdavis
Tweak unicode escape diagnostics
2 parents 0432798 + 30961c9 commit 7a2779a

File tree

6 files changed

+148
-11
lines changed

6 files changed

+148
-11
lines changed

src/libsyntax/parse/lexer/mod.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,36 @@ impl<'a> StringReader<'a> {
945945
self.scan_unicode_escape(delim) && !ascii_only
946946
} else {
947947
let span = self.mk_sp(start, self.pos);
948-
self.sess.span_diagnostic
949-
.struct_span_err(span, "incorrect unicode escape sequence")
950-
.span_help(span,
951-
"format of unicode escape sequences is \
952-
`\\u{…}`")
953-
.emit();
948+
let mut suggestion = "\\u{".to_owned();
949+
let mut err = self.sess.span_diagnostic.struct_span_err(
950+
span,
951+
"incorrect unicode escape sequence",
952+
);
953+
let mut i = 0;
954+
while let (Some(ch), true) = (self.ch, i < 6) {
955+
if ch.is_digit(16) {
956+
suggestion.push(ch);
957+
self.bump();
958+
i += 1;
959+
} else {
960+
break;
961+
}
962+
}
963+
if i != 0 {
964+
suggestion.push('}');
965+
err.span_suggestion_with_applicability(
966+
self.mk_sp(start, self.pos),
967+
"format of unicode escape sequences uses braces",
968+
suggestion,
969+
Applicability::MaybeIncorrect,
970+
);
971+
} else {
972+
err.span_help(
973+
span,
974+
"format of unicode escape sequences is `\\u{...}`",
975+
);
976+
}
977+
err.emit();
954978
false
955979
};
956980
if ascii_only {

src/libsyntax_ext/format.rs

+45
Original file line numberDiff line numberDiff line change
@@ -808,12 +808,57 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
808808
}
809809
('\\', Some((next_pos, 'n'))) |
810810
('\\', Some((next_pos, 't'))) |
811+
('\\', Some((next_pos, '0'))) |
811812
('\\', Some((next_pos, '\\'))) |
812813
('\\', Some((next_pos, '\''))) |
813814
('\\', Some((next_pos, '\"'))) => {
814815
skips.push(*next_pos);
815816
let _ = s.next();
816817
}
818+
('\\', Some((_, 'x'))) if !is_raw => {
819+
for _ in 0..3 { // consume `\xAB` literal
820+
if let Some((pos, _)) = s.next() {
821+
skips.push(pos);
822+
} else {
823+
break;
824+
}
825+
}
826+
}
827+
('\\', Some((_, 'u'))) if !is_raw => {
828+
if let Some((pos, _)) = s.next() {
829+
skips.push(pos);
830+
}
831+
if let Some((next_pos, next_c)) = s.next() {
832+
if next_c == '{' {
833+
skips.push(next_pos);
834+
let mut i = 0; // consume up to 6 hexanumeric chars + closing `}`
835+
while let (Some((next_pos, c)), true) = (s.next(), i < 7) {
836+
if c.is_digit(16) {
837+
skips.push(next_pos);
838+
} else if c == '}' {
839+
skips.push(next_pos);
840+
break;
841+
} else {
842+
break;
843+
}
844+
i += 1;
845+
}
846+
} else if next_c.is_digit(16) {
847+
skips.push(next_pos);
848+
// We suggest adding `{` and `}` when appropriate, accept it here as if
849+
// it were correct
850+
let mut i = 0; // consume up to 6 hexanumeric chars
851+
while let (Some((next_pos, c)), _) = (s.next(), i < 6) {
852+
if c.is_digit(16) {
853+
skips.push(next_pos);
854+
} else {
855+
break;
856+
}
857+
i += 1;
858+
}
859+
}
860+
}
861+
}
817862
_ if eat_ws => { // `take_while(|c| c.is_whitespace())`
818863
eat_ws = false;
819864
}

src/test/ui/fmt/format-string-error-2.rs

+15
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,19 @@ raw { \n
6969
//~^^ ERROR invalid format string
7070
println!("\t{}");
7171
//~^ ERROR 1 positional argument in format string
72+
73+
// note: `\x7B` is `{`
74+
println!("\x7B}\u{8} {", 1);
75+
//~^ ERROR invalid format string: expected `'}'` but string was terminated
76+
77+
println!("\x7B}\u8 {", 1);
78+
//~^ ERROR incorrect unicode escape sequence
79+
//~| ERROR argument never used
80+
81+
// note: raw strings don't escape `\xFF` and `\u{FF}` sequences
82+
println!(r#"\x7B}\u{8} {"#, 1);
83+
//~^ ERROR invalid format string: unmatched `}` found
84+
85+
println!(r#"\x7B}\u8 {"#, 1);
86+
//~^ ERROR invalid format string: unmatched `}` found
7287
}

src/test/ui/fmt/format-string-error-2.stderr

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
error: incorrect unicode escape sequence
2+
--> $DIR/format-string-error-2.rs:77:20
3+
|
4+
LL | println!("/x7B}/u8 {", 1);
5+
| ^^-
6+
| |
7+
| help: format of unicode escape sequences uses braces: `/u{8}`
8+
19
error: invalid format string: expected `'}'`, found `'a'`
210
--> $DIR/format-string-error-2.rs:5:5
311
|
@@ -139,5 +147,39 @@ error: 1 positional argument in format string, but no arguments were given
139147
LL | println!("/t{}");
140148
| ^^
141149

142-
error: aborting due to 14 previous errors
150+
error: invalid format string: expected `'}'` but string was terminated
151+
--> $DIR/format-string-error-2.rs:74:27
152+
|
153+
LL | println!("/x7B}/u{8} {", 1);
154+
| -^ expected `'}'` in format string
155+
| |
156+
| because of this opening brace
157+
|
158+
= note: if you intended to print `{`, you can escape it using `{{`
159+
160+
error: argument never used
161+
--> $DIR/format-string-error-2.rs:77:28
162+
|
163+
LL | println!("/x7B}/u8 {", 1);
164+
| ------------ ^ argument never used
165+
| |
166+
| formatting specifier missing
167+
168+
error: invalid format string: unmatched `}` found
169+
--> $DIR/format-string-error-2.rs:82:21
170+
|
171+
LL | println!(r#"/x7B}/u{8} {"#, 1);
172+
| ^ unmatched `}` in format string
173+
|
174+
= note: if you intended to print `}`, you can escape it using `}}`
175+
176+
error: invalid format string: unmatched `}` found
177+
--> $DIR/format-string-error-2.rs:85:21
178+
|
179+
LL | println!(r#"/x7B}/u8 {"#, 1);
180+
| ^ unmatched `}` in format string
181+
|
182+
= note: if you intended to print `}`, you can escape it using `}}`
183+
184+
error: aborting due to 19 previous errors
143185

src/test/ui/parser/issue-23620-invalid-escapes.rs

+3
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,7 @@ fn main() {
3535
//~^ ERROR invalid character in numeric character escape:
3636
//~^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f]
3737
//~^^^ ERROR incorrect unicode escape sequence
38+
39+
let _ = "\u8f";
40+
//~^ ERROR incorrect unicode escape sequence
3841
}

src/test/ui/parser/issue-23620-invalid-escapes.stderr

+12-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ error: incorrect unicode escape sequence
1616
LL | let _ = b'/u';
1717
| ^^
1818
|
19-
help: format of unicode escape sequences is `/u{}`
19+
help: format of unicode escape sequences is `/u{...}`
2020
--> $DIR/issue-23620-invalid-escapes.rs:10:15
2121
|
2222
LL | let _ = b'/u';
@@ -82,7 +82,7 @@ error: incorrect unicode escape sequence
8282
LL | let _ = b"/u{a4a4} /xf /u";
8383
| ^^
8484
|
85-
help: format of unicode escape sequences is `/u{}`
85+
help: format of unicode escape sequences is `/u{...}`
8686
--> $DIR/issue-23620-invalid-escapes.rs:28:28
8787
|
8888
LL | let _ = b"/u{a4a4} /xf /u";
@@ -112,11 +112,19 @@ error: incorrect unicode escape sequence
112112
LL | let _ = "/xf /u";
113113
| ^^
114114
|
115-
help: format of unicode escape sequences is `/u{}`
115+
help: format of unicode escape sequences is `/u{...}`
116116
--> $DIR/issue-23620-invalid-escapes.rs:34:18
117117
|
118118
LL | let _ = "/xf /u";
119119
| ^^
120120

121-
error: aborting due to 17 previous errors
121+
error: incorrect unicode escape sequence
122+
--> $DIR/issue-23620-invalid-escapes.rs:39:14
123+
|
124+
LL | let _ = "/u8f";
125+
| ^^--
126+
| |
127+
| help: format of unicode escape sequences uses braces: `/u{8f}`
128+
129+
error: aborting due to 18 previous errors
122130

0 commit comments

Comments
 (0)