1- use core:: { char, fmt, mem} ;
1+ use core:: convert:: TryFrom ;
2+ use core:: { char, fmt, iter, mem} ;
23
34#[ allow( unused_macros) ]
45macro_rules! write {
@@ -264,6 +265,30 @@ impl<'s> fmt::Display for Ident<'s> {
264265 }
265266}
266267
268+ /// Sequence of lowercase hexadecimal nibbles (`0-9a-f`), used by leaf consts.
269+ struct HexNibbles < ' s > {
270+ nibbles : & ' s str ,
271+ }
272+
273+ impl < ' s > HexNibbles < ' s > {
274+ /// Decode an integer value (with the "most significant nibble" first),
275+ /// returning `None` if it can't fit in an `u64`.
276+ // FIXME(eddyb) should this "just" use `u128` instead?
277+ fn try_parse_uint ( & self ) -> Option < u64 > {
278+ let nibbles = self . nibbles . trim_start_matches ( "0" ) ;
279+
280+ if nibbles. len ( ) > 16 {
281+ return None ;
282+ }
283+
284+ let mut v = 0 ;
285+ for nibble in nibbles. chars ( ) {
286+ v = ( v << 4 ) | ( nibble. to_digit ( 16 ) . unwrap ( ) as u64 ) ;
287+ }
288+ Some ( v)
289+ }
290+ }
291+
267292fn basic_type ( tag : u8 ) -> Option < & ' static str > {
268293 Some ( match tag {
269294 b'b' => "bool" ,
@@ -331,7 +356,7 @@ impl<'s> Parser<'s> {
331356 Ok ( b)
332357 }
333358
334- fn hex_nibbles ( & mut self ) -> Result < & ' s str , ParseError > {
359+ fn hex_nibbles ( & mut self ) -> Result < HexNibbles < ' s > , ParseError > {
335360 let start = self . next ;
336361 loop {
337362 match self . next ( ) ? {
@@ -340,7 +365,9 @@ impl<'s> Parser<'s> {
340365 _ => return Err ( ParseError :: Invalid ) ,
341366 }
342367 }
343- Ok ( & self . sym [ start..self . next - 1 ] )
368+ Ok ( HexNibbles {
369+ nibbles : & self . sym [ start..self . next - 1 ] ,
370+ } )
344371 }
345372
346373 fn digit_10 ( & mut self ) -> Result < u8 , ParseError > {
@@ -577,6 +604,35 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
577604 Ok ( ( ) )
578605 }
579606
607+ /// Output the given `char`s (escaped using `char::escape_debug`), with the
608+ /// whole sequence wrapped in quotes, for either a `char` or `&str` literal,
609+ /// if printing isn't being skipped.
610+ fn print_quoted_escaped_chars (
611+ & mut self ,
612+ quote : char ,
613+ chars : impl Iterator < Item = char > ,
614+ ) -> fmt:: Result {
615+ if let Some ( out) = & mut self . out {
616+ use core:: fmt:: Write ;
617+
618+ out. write_char ( quote) ?;
619+ for c in chars {
620+ // Special-case not escaping a single/double quote, when
621+ // inside the opposite kind of quote.
622+ if matches ! ( ( quote, c) , ( '\'' , '"' ) | ( '"' , '\'' ) ) {
623+ out. write_char ( c) ?;
624+ continue ;
625+ }
626+
627+ for escaped in c. escape_debug ( ) {
628+ out. write_char ( escaped) ?;
629+ }
630+ }
631+ out. write_char ( quote) ?;
632+ }
633+ Ok ( ( ) )
634+ }
635+
580636 /// Print the lifetime according to the previously decoded index.
581637 /// An index of `0` always refers to `'_`, but starting with `1`,
582638 /// indices refer to late-bound lifetimes introduced by a binder.
@@ -946,102 +1002,68 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
9461002 }
9471003
9481004 fn print_const ( & mut self ) -> fmt:: Result {
949- parse ! ( self , push_depth) ;
950-
951- if self . eat ( b'B' ) {
952- self . print_backref ( Self :: print_const) ?;
953-
954- self . pop_depth ( ) ;
955- return Ok ( ( ) ) ;
956- }
1005+ let tag = parse ! ( self , next) ;
9571006
958- let ty_tag = parse ! ( self , next ) ;
1007+ parse ! ( self , push_depth ) ;
9591008
960- if ty_tag == b'p' {
961- // We don't encode the type if the value is a placeholder.
962- self . print ( "_" ) ?;
1009+ match tag {
1010+ b'p' => self . print ( "_" ) ?,
9631011
964- self . pop_depth ( ) ;
965- return Ok ( ( ) ) ;
966- }
1012+ // Primitive leaves with hex-encoded values (see `basic_type`).
1013+ b'h' | b't' | b'm' | b'y' | b'o' | b'j' => self . print_const_uint ( tag) ?,
1014+ b'a' | b's' | b'l' | b'x' | b'n' | b'i' => {
1015+ if self . eat ( b'n' ) {
1016+ self . print ( "-" ) ?;
1017+ }
9671018
968- match ty_tag {
969- // Unsigned integer types.
970- b'h' | b't' | b'm' | b'y' | b'o' | b'j' => self . print_const_uint ( ) ?,
971- // Signed integer types.
972- b'a' | b's' | b'l' | b'x' | b'n' | b'i' => self . print_const_int ( ) ?,
973- // Bool.
974- b'b' => self . print_const_bool ( ) ?,
975- // Char.
976- b'c' => self . print_const_char ( ) ?,
977-
978- // This branch ought to be unreachable.
979- _ => invalid ! ( self ) ,
980- } ;
1019+ self . print_const_uint ( tag) ?;
1020+ }
1021+ b'b' => match parse ! ( self , hex_nibbles) . try_parse_uint ( ) {
1022+ Some ( 0 ) => self . print ( "false" ) ?,
1023+ Some ( 1 ) => self . print ( "true" ) ?,
1024+ _ => invalid ! ( self ) ,
1025+ } ,
1026+ b'c' => {
1027+ let valid_char = parse ! ( self , hex_nibbles)
1028+ . try_parse_uint ( )
1029+ . and_then ( |v| u32:: try_from ( v) . ok ( ) )
1030+ . and_then ( char:: from_u32) ;
1031+ match valid_char {
1032+ Some ( c) => self . print_quoted_escaped_chars ( '\'' , iter:: once ( c) ) ?,
1033+ None => invalid ! ( self ) ,
1034+ }
1035+ }
9811036
982- if let Some ( out) = & mut self . out {
983- if !out. alternate ( ) {
984- self . print ( ": " ) ?;
985- let ty = basic_type ( ty_tag) . unwrap ( ) ;
986- self . print ( ty) ?;
1037+ b'B' => {
1038+ self . print_backref ( Self :: print_const) ?;
9871039 }
1040+ _ => invalid ! ( self ) ,
9881041 }
9891042
9901043 self . pop_depth ( ) ;
9911044 Ok ( ( ) )
9921045 }
9931046
994- fn print_const_uint ( & mut self ) -> fmt:: Result {
1047+ fn print_const_uint ( & mut self , ty_tag : u8 ) -> fmt:: Result {
9951048 let hex = parse ! ( self , hex_nibbles) ;
9961049
997- // Print anything that doesn't fit in `u64` verbatim.
998- if hex. len ( ) > 16 {
999- self . print ( "0x" ) ?;
1000- return self . print ( hex) ;
1001- }
1002-
1003- let mut v = 0 ;
1004- for c in hex. chars ( ) {
1005- v = ( v << 4 ) | ( c. to_digit ( 16 ) . unwrap ( ) as u64 ) ;
1006- }
1007- self . print ( v)
1008- }
1009-
1010- fn print_const_int ( & mut self ) -> fmt:: Result {
1011- if self . eat ( b'n' ) {
1012- self . print ( "-" ) ?;
1013- }
1014-
1015- self . print_const_uint ( )
1016- }
1050+ match hex. try_parse_uint ( ) {
1051+ Some ( v) => self . print ( v) ?,
10171052
1018- fn print_const_bool ( & mut self ) -> fmt:: Result {
1019- match parse ! ( self , hex_nibbles) . as_bytes ( ) {
1020- b"0" => self . print ( "false" ) ,
1021- b"1" => self . print ( "true" ) ,
1022- _ => invalid ! ( self ) ,
1023- }
1024- }
1025-
1026- fn print_const_char ( & mut self ) -> fmt:: Result {
1027- let hex = parse ! ( self , hex_nibbles) ;
1028-
1029- // Valid `char`s fit in `u32`.
1030- if hex. len ( ) > 8 {
1031- invalid ! ( self ) ;
1053+ // Print anything that doesn't fit in `u64` verbatim.
1054+ None => {
1055+ self . print ( "0x" ) ?;
1056+ self . print ( hex. nibbles ) ?;
1057+ }
10321058 }
10331059
1034- let mut v = 0 ;
1035- for c in hex. chars ( ) {
1036- v = ( v << 4 ) | ( c. to_digit ( 16 ) . unwrap ( ) as u32 ) ;
1037- }
1038- if let Some ( c) = char:: from_u32 ( v) {
1039- if let Some ( out) = & mut self . out {
1040- fmt:: Debug :: fmt ( & c, out) ?;
1060+ if let Some ( out) = & mut self . out {
1061+ if !out. alternate ( ) {
1062+ let ty = basic_type ( ty_tag) . unwrap ( ) ;
1063+ self . print ( ty) ?;
10411064 }
1042- } else {
1043- invalid ! ( self ) ;
10441065 }
1066+
10451067 Ok ( ( ) )
10461068 }
10471069}
@@ -1050,6 +1072,11 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
10501072mod tests {
10511073 use std:: prelude:: v1:: * ;
10521074
1075+ macro_rules! t {
1076+ ( $a: expr, $b: expr) => { {
1077+ assert_eq!( format!( "{}" , :: demangle( $a) ) , $b) ;
1078+ } } ;
1079+ }
10531080 macro_rules! t_nohash {
10541081 ( $a: expr, $b: expr) => { {
10551082 assert_eq!( format!( "{:#}" , :: demangle( $a) ) , $b) ;
@@ -1060,6 +1087,23 @@ mod tests {
10601087 t_nohash!( concat!( "_RMC0" , $a) , concat!( "<" , $b, ">" ) )
10611088 } ;
10621089 }
1090+ macro_rules! t_const {
1091+ ( $mangled: expr, $value: expr) => {
1092+ t_nohash!(
1093+ concat!( "_RIC0K" , $mangled, "E" ) ,
1094+ concat!( "::<" , $value, ">" )
1095+ )
1096+ } ;
1097+ }
1098+ macro_rules! t_const_suffixed {
1099+ ( $mangled: expr, $value: expr, $value_ty_suffix: expr) => { {
1100+ t_const!( $mangled, $value) ;
1101+ t!(
1102+ concat!( "_RIC0K" , $mangled, "E" ) ,
1103+ concat!( "[0]::<" , $value, $value_ty_suffix, ">" )
1104+ ) ;
1105+ } } ;
1106+ }
10631107
10641108 #[ test]
10651109 fn demangle_crate_with_leading_digit ( ) {
@@ -1095,49 +1139,29 @@ mod tests {
10951139 }
10961140
10971141 #[ test]
1098- fn demangle_const_generics ( ) {
1142+ fn demangle_const_generics_preview ( ) {
10991143 // NOTE(eddyb) this was hand-written, before rustc had working
11001144 // const generics support (but the mangling format did include them).
11011145 t_nohash_type ! (
11021146 "INtC8arrayvec8ArrayVechKj7b_E" ,
11031147 "arrayvec::ArrayVec<u8, 123>"
11041148 ) ;
1105- t_nohash ! (
1106- "_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E" ,
1107- "<const_generic::Unsigned<11>>"
1108- ) ;
1109- t_nohash ! (
1110- "_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E" ,
1111- "<const_generic::Signed<152>>"
1112- ) ;
1113- t_nohash ! (
1114- "_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E" ,
1115- "<const_generic::Signed<-11>>"
1116- ) ;
1117- t_nohash ! (
1118- "_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E" ,
1119- "<const_generic::Bool<false>>"
1120- ) ;
1121- t_nohash ! (
1122- "_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E" ,
1123- "<const_generic::Bool<true>>"
1124- ) ;
1125- t_nohash ! (
1126- "_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E" ,
1127- "<const_generic::Char<'v'>>"
1128- ) ;
1129- t_nohash ! (
1130- "_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E" ,
1131- "<const_generic::Char<'\\ n'>>"
1132- ) ;
1133- t_nohash ! (
1134- "_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E" ,
1135- "<const_generic::Char<'∂'>>"
1136- ) ;
1137- t_nohash ! (
1138- "_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO" ,
1139- "<const_generic::Foo<_>>::foo::FOO"
1140- ) ;
1149+ t_const_suffixed ! ( "j7b_" , "123" , "usize" ) ;
1150+ }
1151+
1152+ #[ test]
1153+ fn demangle_min_const_generics ( ) {
1154+ t_const ! ( "p" , "_" ) ;
1155+ t_const_suffixed ! ( "hb_" , "11" , "u8" ) ;
1156+ t_const_suffixed ! ( "off00ff00ff00ff00ff_" , "0xff00ff00ff00ff00ff" , "u128" ) ;
1157+ t_const_suffixed ! ( "s98_" , "152" , "i16" ) ;
1158+ t_const_suffixed ! ( "anb_" , "-11" , "i8" ) ;
1159+ t_const ! ( "b0_" , "false" ) ;
1160+ t_const ! ( "b1_" , "true" ) ;
1161+ t_const ! ( "c76_" , "'v'" ) ;
1162+ t_const ! ( "c22_" , r#"'"'"# ) ;
1163+ t_const ! ( "ca_" , "'\\ n'" ) ;
1164+ t_const ! ( "c2202_" , "'∂'" ) ;
11411165 }
11421166
11431167 #[ test]
0 commit comments