@@ -650,10 +650,13 @@ impl<'a> StringReader<'a> {
650650 /// token, and updates the interner
651651 fn next_token_inner ( & mut self ) -> token:: Token {
652652 let c = self . curr ;
653- if ident_start ( c) && ! self . nextch_is ( '"' ) && ! self . nextch_is ( '#' ) {
653+ if ident_start ( c) && match ( c . unwrap ( ) , self . nextch ( ) ) {
654654 // Note: r as in r" or r#" is part of a raw string literal,
655- // not an identifier, and is handled further down.
656-
655+ // b as in b' is part of a byte literal.
656+ // They are not identifiers, and are handled further down.
657+ ( 'r' , Some ( '"' ) ) | ( 'r' , Some ( '#' ) ) | ( 'b' , Some ( '\'' ) ) => false ,
658+ _ => true
659+ } {
657660 let start = self . last_pos ;
658661 while ident_continue ( self . curr ) {
659662 self . bump ( ) ;
@@ -854,6 +857,65 @@ impl<'a> StringReader<'a> {
854857 self . bump ( ) ; // advance curr past token
855858 return token:: LIT_CHAR ( c2) ;
856859 }
860+ 'b' => {
861+ self . bump ( ) ;
862+ assert ! ( self . curr_is( '\'' ) , "Should have been a token::IDENT" ) ;
863+ self . bump ( ) ;
864+ let start = self . last_pos ;
865+
866+ // the eof will be picked up by the final `'` check below
867+ let mut c2 = self . curr . unwrap_or ( '\x00' ) ;
868+ self . bump ( ) ;
869+
870+ match c2 {
871+ '\\' => {
872+ // '\X' for some X must be a character constant:
873+ let escaped = self . curr ;
874+ let escaped_pos = self . last_pos ;
875+ self . bump ( ) ;
876+ match escaped {
877+ None => { }
878+ Some ( e) => {
879+ c2 = match e {
880+ 'n' => '\n' ,
881+ 'r' => '\r' ,
882+ 't' => '\t' ,
883+ '\\' => '\\' ,
884+ '\'' => '\'' ,
885+ '"' => '"' ,
886+ '0' => '\x00' ,
887+ 'x' => self . scan_numeric_escape ( 2 u, '\'' ) ,
888+ c2 => {
889+ self . err_span_char ( escaped_pos, self . last_pos ,
890+ "unknown byte escape" , c2) ;
891+ c2
892+ }
893+ }
894+ }
895+ }
896+ }
897+ '\t' | '\n' | '\r' | '\'' => {
898+ self . err_span_char ( start, self . last_pos ,
899+ "byte constant must be escaped" , c2) ;
900+ }
901+ _ if c2 > '\x7F' => {
902+ self . err_span_char ( start, self . last_pos ,
903+ "byte constant must be ASCII. \
904+ Use a \\ xHH escape for a non-ASCII byte", c2) ;
905+ }
906+ _ => { }
907+ }
908+ if !self . curr_is ( '\'' ) {
909+ self . fatal_span_verbose (
910+ // Byte offsetting here is okay because the
911+ // character before position `start` are an
912+ // ascii single quote and ascii 'b'.
913+ start - BytePos ( 2 ) , self . last_pos ,
914+ "unterminated byte constant" . to_string ( ) ) ;
915+ }
916+ self . bump ( ) ; // advance curr past token
917+ return token:: LIT_BYTE ( c2 as u8 ) ;
918+ }
857919 '"' => {
858920 let mut accum_str = String :: new ( ) ;
859921 let start_bpos = self . last_pos ;
0 commit comments