@@ -13,6 +13,8 @@ pub(crate) fn emit_unescape_error(
13
13
lit : & str ,
14
14
// full span of the literal, including quotes
15
15
span_with_quotes : Span ,
16
+ // interior span of the literal, without quotes
17
+ span : Span ,
16
18
mode : Mode ,
17
19
// range of the error inside `lit`
18
20
range : Range < usize > ,
@@ -26,13 +28,6 @@ pub(crate) fn emit_unescape_error(
26
28
range,
27
29
error
28
30
) ;
29
- let span = {
30
- let Range { start, end } = range;
31
- let ( start, end) = ( start as u32 , end as u32 ) ;
32
- let lo = span_with_quotes. lo ( ) + BytePos ( start + 1 ) ;
33
- let hi = lo + BytePos ( end - start) ;
34
- span_with_quotes. with_lo ( lo) . with_hi ( hi)
35
- } ;
36
31
let last_char = || {
37
32
let c = lit[ range. clone ( ) ] . chars ( ) . rev ( ) . next ( ) . unwrap ( ) ;
38
33
let span = span. with_lo ( span. hi ( ) - BytePos ( c. len_utf8 ( ) as u32 ) ) ;
@@ -42,20 +37,22 @@ pub(crate) fn emit_unescape_error(
42
37
EscapeError :: LoneSurrogateUnicodeEscape => {
43
38
handler
44
39
. struct_span_err ( span, "invalid unicode character escape" )
40
+ . span_label ( span, "invalid escape" )
45
41
. help ( "unicode escape must not be a surrogate" )
46
42
. emit ( ) ;
47
43
}
48
44
EscapeError :: OutOfRangeUnicodeEscape => {
49
45
handler
50
46
. struct_span_err ( span, "invalid unicode character escape" )
47
+ . span_label ( span, "invalid escape" )
51
48
. help ( "unicode escape must be at most 10FFFF" )
52
49
. emit ( ) ;
53
50
}
54
51
EscapeError :: MoreThanOneChar => {
55
- let msg = if mode. is_bytes ( ) {
56
- " if you meant to write a byte string literal, use double quotes"
52
+ let ( prefix , msg) = if mode. is_bytes ( ) {
53
+ ( "b" , " if you meant to write a byte string literal, use double quotes")
57
54
} else {
58
- " if you meant to write a `str` literal, use double quotes"
55
+ ( "" , " if you meant to write a `str` literal, use double quotes")
59
56
} ;
60
57
61
58
handler
@@ -66,31 +63,44 @@ pub(crate) fn emit_unescape_error(
66
63
. span_suggestion (
67
64
span_with_quotes,
68
65
msg,
69
- format ! ( "\" {}\" " , lit) ,
66
+ format ! ( "{} \" {}\" " , prefix , lit) ,
70
67
Applicability :: MachineApplicable ,
71
68
)
72
69
. emit ( ) ;
73
70
}
74
71
EscapeError :: EscapeOnlyChar => {
75
- let ( c, _span ) = last_char ( ) ;
72
+ let ( c, char_span ) = last_char ( ) ;
76
73
77
- let mut msg = if mode. is_bytes ( ) {
78
- "byte constant must be escaped: "
74
+ let msg = if mode. is_bytes ( ) {
75
+ "byte constant must be escaped"
79
76
} else {
80
- "character constant must be escaped: "
81
- }
82
- . to_string ( ) ;
83
- push_escaped_char ( & mut msg, c) ;
84
-
85
- handler. span_err ( span, msg. as_str ( ) )
77
+ "character constant must be escaped"
78
+ } ;
79
+ handler
80
+ . struct_span_err ( span, & format ! ( "{}: `{}`" , msg, escaped_char( c) ) )
81
+ . span_suggestion (
82
+ char_span,
83
+ "escape the character" ,
84
+ c. escape_default ( ) . to_string ( ) ,
85
+ Applicability :: MachineApplicable ,
86
+ )
87
+ . emit ( )
86
88
}
87
89
EscapeError :: BareCarriageReturn => {
88
90
let msg = if mode. in_double_quotes ( ) {
89
- "bare CR not allowed in string, use \\ r instead"
91
+ "bare CR not allowed in string, use ` \\ r` instead"
90
92
} else {
91
- "character constant must be escaped: \\ r"
93
+ "character constant must be escaped: ` \\ r` "
92
94
} ;
93
- handler. span_err ( span, msg) ;
95
+ handler
96
+ . struct_span_err ( span, msg)
97
+ . span_suggestion (
98
+ span,
99
+ "escape the character" ,
100
+ "\\ r" . to_string ( ) ,
101
+ Applicability :: MachineApplicable ,
102
+ )
103
+ . emit ( ) ;
94
104
}
95
105
EscapeError :: BareCarriageReturnInRawString => {
96
106
assert ! ( mode. in_double_quotes( ) ) ;
@@ -102,21 +112,22 @@ pub(crate) fn emit_unescape_error(
102
112
103
113
let label =
104
114
if mode. is_bytes ( ) { "unknown byte escape" } else { "unknown character escape" } ;
105
- let mut msg = label. to_string ( ) ;
106
- msg. push_str ( ": " ) ;
107
- push_escaped_char ( & mut msg, c) ;
108
-
109
- let mut diag = handler. struct_span_err ( span, msg. as_str ( ) ) ;
115
+ let ec = escaped_char ( c) ;
116
+ let mut diag = handler. struct_span_err ( span, & format ! ( "{}: `{}`" , label, ec) ) ;
110
117
diag. span_label ( span, label) ;
111
118
if c == '{' || c == '}' && !mode. is_bytes ( ) {
112
119
diag. help (
113
- "if used in a formatting string, \
114
- curly braces are escaped with `{{` and `}}`",
120
+ "if used in a formatting string, curly braces are escaped with `{{` and `}}`" ,
115
121
) ;
116
122
} else if c == '\r' {
117
123
diag. help (
118
- "this is an isolated carriage return; \
119
- consider checking your editor and version control settings",
124
+ "this is an isolated carriage return; consider checking your editor and \
125
+ version control settings",
126
+ ) ;
127
+ } else {
128
+ diag. help (
129
+ "for more information, visit \
130
+ <https://static.rust-lang.org/doc/master/reference.html#literals>",
120
131
) ;
121
132
}
122
133
diag. emit ( ) ;
@@ -127,45 +138,70 @@ pub(crate) fn emit_unescape_error(
127
138
EscapeError :: InvalidCharInHexEscape | EscapeError :: InvalidCharInUnicodeEscape => {
128
139
let ( c, span) = last_char ( ) ;
129
140
130
- let mut msg = if error == EscapeError :: InvalidCharInHexEscape {
131
- "invalid character in numeric character escape: "
141
+ let msg = if error == EscapeError :: InvalidCharInHexEscape {
142
+ "invalid character in numeric character escape"
132
143
} else {
133
- "invalid character in unicode escape: "
134
- }
135
- . to_string ( ) ;
136
- push_escaped_char ( & mut msg, c) ;
144
+ "invalid character in unicode escape"
145
+ } ;
146
+ let c = escaped_char ( c) ;
137
147
138
- handler. span_err ( span, msg. as_str ( ) )
148
+ handler
149
+ . struct_span_err ( span, & format ! ( "{}: `{}`" , msg, c) )
150
+ . span_label ( span, msg)
151
+ . emit ( ) ;
139
152
}
140
153
EscapeError :: NonAsciiCharInByte => {
141
154
assert ! ( mode. is_bytes( ) ) ;
142
- let ( _c, span) = last_char ( ) ;
143
- handler. span_err (
144
- span,
145
- "byte constant must be ASCII. \
146
- Use a \\ xHH escape for a non-ASCII byte",
147
- )
155
+ let ( c, span) = last_char ( ) ;
156
+ handler
157
+ . struct_span_err ( span, "non-ASCII character in byte constant" )
158
+ . span_label ( span, "byte constant must be ASCII" )
159
+ . span_suggestion (
160
+ span,
161
+ "use a \\ xHH escape for a non-ASCII byte" ,
162
+ format ! ( "\\ x{:X}" , c as u32 ) ,
163
+ Applicability :: MachineApplicable ,
164
+ )
165
+ . emit ( ) ;
148
166
}
149
167
EscapeError :: NonAsciiCharInByteString => {
150
168
assert ! ( mode. is_bytes( ) ) ;
151
169
let ( _c, span) = last_char ( ) ;
152
- handler. span_err ( span, "raw byte string must be ASCII" )
170
+ handler
171
+ . struct_span_err ( span, "raw byte string must be ASCII" )
172
+ . span_label ( span, "must be ASCII" )
173
+ . emit ( ) ;
174
+ }
175
+ EscapeError :: OutOfRangeHexEscape => {
176
+ handler
177
+ . struct_span_err ( span, "out of range hex escape" )
178
+ . span_label ( span, "must be a character in the range [\\ x00-\\ x7f]" )
179
+ . emit ( ) ;
153
180
}
154
- EscapeError :: OutOfRangeHexEscape => handler. span_err (
155
- span,
156
- "this form of character escape may only be used \
157
- with characters in the range [\\ x00-\\ x7f]",
158
- ) ,
159
181
EscapeError :: LeadingUnderscoreUnicodeEscape => {
160
- let ( _c, span) = last_char ( ) ;
161
- handler. span_err ( span, "invalid start of unicode escape" )
182
+ let ( c, span) = last_char ( ) ;
183
+ let msg = "invalid start of unicode escape" ;
184
+ handler
185
+ . struct_span_err ( span, & format ! ( "{}: `{}`" , msg, c) )
186
+ . span_label ( span, msg)
187
+ . emit ( ) ;
162
188
}
163
189
EscapeError :: OverlongUnicodeEscape => {
164
- handler. span_err ( span , "overlong unicode escape (must have at most 6 hex digits)" )
165
- }
166
- EscapeError :: UnclosedUnicodeEscape => {
167
- handler . span_err ( span , "unterminated unicode escape (needed a `}`)" )
190
+ handler
191
+ . struct_span_err ( span , "overlong unicode escape" )
192
+ . span_label ( span , "must have at most 6 hex digits" )
193
+ . emit ( ) ;
168
194
}
195
+ EscapeError :: UnclosedUnicodeEscape => handler
196
+ . struct_span_err ( span, "unterminated unicode escape" )
197
+ . span_label ( span, "missing a closing `}`" )
198
+ . span_suggestion_verbose (
199
+ span. shrink_to_hi ( ) ,
200
+ "terminate the unicode escape" ,
201
+ "}" . to_string ( ) ,
202
+ Applicability :: MaybeIncorrect ,
203
+ )
204
+ . emit ( ) ,
169
205
EscapeError :: NoBraceInUnicodeEscape => {
170
206
let msg = "incorrect unicode escape sequence" ;
171
207
let mut diag = handler. struct_span_err ( span, msg) ;
@@ -195,28 +231,38 @@ pub(crate) fn emit_unescape_error(
195
231
196
232
diag. emit ( ) ;
197
233
}
198
- EscapeError :: UnicodeEscapeInByte => handler. span_err (
199
- span,
200
- "unicode escape sequences cannot be used \
201
- as a byte or in a byte string",
202
- ) ,
234
+ EscapeError :: UnicodeEscapeInByte => {
235
+ let msg = "unicode escape in byte string" ;
236
+ handler
237
+ . struct_span_err ( span, msg)
238
+ . span_label ( span, msg)
239
+ . help ( "unicode escape sequences cannot be used as a byte or in a byte string" )
240
+ . emit ( ) ;
241
+ }
203
242
EscapeError :: EmptyUnicodeEscape => {
204
- handler. span_err ( span, "empty unicode escape (must have at least 1 hex digit)" )
243
+ handler
244
+ . struct_span_err ( span, "empty unicode escape" )
245
+ . span_label ( span, "this escape must have at least 1 hex digit" )
246
+ . emit ( ) ;
247
+ }
248
+ EscapeError :: ZeroChars => {
249
+ let msg = "empty character literal" ;
250
+ handler. struct_span_err ( span, msg) . span_label ( span, msg) . emit ( )
251
+ }
252
+ EscapeError :: LoneSlash => {
253
+ let msg = "invalid trailing slash in literal" ;
254
+ handler. struct_span_err ( span, msg) . span_label ( span, msg) . emit ( ) ;
205
255
}
206
- EscapeError :: ZeroChars => handler. span_err ( span, "empty character literal" ) ,
207
- EscapeError :: LoneSlash => handler. span_err ( span, "invalid trailing slash in literal" ) ,
208
256
}
209
257
}
210
258
211
259
/// Pushes a character to a message string for error reporting
212
- pub ( crate ) fn push_escaped_char ( msg : & mut String , c : char ) {
260
+ pub ( crate ) fn escaped_char ( c : char ) -> String {
213
261
match c {
214
262
'\u{20}' ..='\u{7e}' => {
215
263
// Don't escape \, ' or " for user-facing messages
216
- msg. push ( c) ;
217
- }
218
- _ => {
219
- msg. extend ( c. escape_default ( ) ) ;
264
+ c. to_string ( )
220
265
}
266
+ _ => c. escape_default ( ) . to_string ( ) ,
221
267
}
222
268
}
0 commit comments