@@ -356,8 +356,10 @@ where
356
356
let start = src. len ( ) - chars. as_str ( ) . len ( ) - c. len_utf8 ( ) ;
357
357
let res = match c {
358
358
'\\' => {
359
- match chars. clone ( ) . next ( ) {
359
+ let mut chars_clone = chars. clone ( ) ;
360
+ match chars_clone. next ( ) {
360
361
Some ( '\n' ) => {
362
+ chars = chars_clone;
361
363
// Rust language specification requires us to skip whitespaces
362
364
// if unescaped '\' character is followed by '\n'.
363
365
// For details see [Rust language reference]
@@ -379,30 +381,42 @@ where
379
381
}
380
382
}
381
383
384
+ /// Skip ASCII whitespace, except for the formfeed character
385
+ /// (see [this issue](https://github.com/rust-lang/rust/issues/136600)).
386
+ /// Warns on unescaped newline and following non-ASCII whitespace.
382
387
fn skip_ascii_whitespace < F > ( chars : & mut Chars < ' _ > , start : usize , callback : & mut F )
383
388
where
384
389
F : FnMut ( Range < usize > , EscapeError ) ,
385
390
{
386
- let tail = chars. as_str ( ) ;
387
- let first_non_space = tail
388
- . bytes ( )
389
- . position ( |b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r' )
390
- . unwrap_or ( tail. len ( ) ) ;
391
- if tail[ 1 ..first_non_space] . contains ( '\n' ) {
392
- // The +1 accounts for the escaping slash.
393
- let end = start + first_non_space + 1 ;
391
+ let mut spaces = 0 ;
392
+ let mut contains_nl = false ;
393
+
394
+ for byte in chars. as_str ( ) . bytes ( ) {
395
+ match byte {
396
+ b' ' | b'\t' | b'\r' => {
397
+ spaces += 1 ;
398
+ }
399
+ b'\n' => {
400
+ spaces += 1 ;
401
+ contains_nl = true ;
402
+ }
403
+ _ => break ,
404
+ }
405
+ }
406
+ * chars = chars. as_str ( ) [ spaces..] . chars ( ) ;
407
+
408
+ // the escaping slash and newline characters add 2 bytes
409
+ let end = start + 2 + spaces;
410
+
411
+ if contains_nl {
394
412
callback ( start..end, EscapeError :: MultipleSkippedLinesWarning ) ;
395
413
}
396
- let tail = & tail[ first_non_space..] ;
397
- if let Some ( c) = tail. chars ( ) . next ( ) {
414
+ if let Some ( c) = chars. clone ( ) . next ( ) {
398
415
if c. is_whitespace ( ) {
399
- // For error reporting, we would like the span to contain the character that was not
400
- // skipped. The +1 is necessary to account for the leading \ that started the escape.
401
- let end = start + first_non_space + c. len_utf8 ( ) + 1 ;
402
- callback ( start..end, EscapeError :: UnskippedWhitespaceWarning ) ;
416
+ // for error reporting, include the character that was not skipped in the span
417
+ callback ( start..end + c. len_utf8 ( ) , EscapeError :: UnskippedWhitespaceWarning ) ;
403
418
}
404
419
}
405
- * chars = tail. chars ( ) ;
406
420
}
407
421
408
422
/// Takes a contents of a string literal (without quotes) and produces a
0 commit comments