@@ -356,11 +356,10 @@ where
356356        let  start = src. len ( )  - chars. as_str ( ) . len ( )  - c. len_utf8 ( ) ; 
357357        let  res = match  c { 
358358            '\\'  => { 
359-                 match  chars. clone ( ) . next ( )  { 
360-                     Some ( '\n' )  => { 
361-                         // Rust language specification requires us to skip whitespaces 
362-                         // if unescaped '\' character is followed by '\n'. 
363-                         // For details see [Rust language reference] 
359+                 match  chars. as_str ( ) . as_bytes ( ) . first ( )  { 
360+                     Some ( b'\n' )  => { 
361+                         let  _ = chars. next ( ) ; 
362+                         // skip whitespace for backslash newline, see [Rust language reference] 
364363                        // (https://doc.rust-lang.org/reference/tokens.html#string-literals). 
365364                        skip_ascii_whitespace ( & mut  chars,  start,  & mut  |range,  err| { 
366365                            callback ( range,  Err ( err) ) 
@@ -379,30 +378,38 @@ where
379378    } 
380379} 
381380
381+ /// Skip ASCII whitespace, except for the formfeed character 
382+ /// (see [this issue](https://github.com/rust-lang/rust/issues/136600)). 
383+ /// Warns on unescaped newline and following non-ASCII whitespace. 
382384fn  skip_ascii_whitespace < F > ( chars :  & mut  Chars < ' _ > ,  start :  usize ,  callback :  & mut  F ) 
383385where 
384386    F :  FnMut ( Range < usize > ,  EscapeError ) , 
385387{ 
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 ; 
388+     let  mut  spaces = 0 ; 
389+     let  mut  contains_nl = false ; 
390+ 
391+     for  byte in  chars. as_str ( ) . bytes ( )  { 
392+         let  is_space = b" \t \n \r " . contains ( & byte) ; 
393+         spaces += is_space as  usize ; 
394+         contains_nl |= byte == b'\n' ; 
395+         if  !is_space { 
396+             break ; 
397+         } 
398+     } 
399+     * chars = chars. as_str ( ) [ spaces..] . chars ( ) ; 
400+ 
401+     // the escaping slash and newline characters add 2 bytes 
402+     let  end = start + 2  + spaces; 
403+ 
404+     if  contains_nl { 
394405        callback ( start..end,  EscapeError :: MultipleSkippedLinesWarning ) ; 
395406    } 
396-     let  tail = & tail[ first_non_space..] ; 
397-     if  let  Some ( c)  = tail. chars ( ) . next ( )  { 
407+     if  let  Some ( c)  = chars. clone ( ) . next ( )  { 
398408        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 ) ; 
409+             // for error reporting, include the character that was not skipped in the span 
410+             callback ( start..end + c. len_utf8 ( ) ,  EscapeError :: UnskippedWhitespaceWarning ) ; 
403411        } 
404412    } 
405-     * chars = tail. chars ( ) ; 
406413} 
407414
408415/// Takes a contents of a string literal (without quotes) and produces a 
0 commit comments