1
- use core:: { char, fmt, mem} ;
1
+ use core:: convert:: TryFrom ;
2
+ use core:: { char, fmt, iter, mem} ;
2
3
3
4
#[ allow( unused_macros) ]
4
5
macro_rules! write {
@@ -264,6 +265,30 @@ impl<'s> fmt::Display for Ident<'s> {
264
265
}
265
266
}
266
267
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
+
267
292
fn basic_type ( tag : u8 ) -> Option < & ' static str > {
268
293
Some ( match tag {
269
294
b'b' => "bool" ,
@@ -331,7 +356,7 @@ impl<'s> Parser<'s> {
331
356
Ok ( b)
332
357
}
333
358
334
- fn hex_nibbles ( & mut self ) -> Result < & ' s str , ParseError > {
359
+ fn hex_nibbles ( & mut self ) -> Result < HexNibbles < ' s > , ParseError > {
335
360
let start = self . next ;
336
361
loop {
337
362
match self . next ( ) ? {
@@ -340,7 +365,9 @@ impl<'s> Parser<'s> {
340
365
_ => return Err ( ParseError :: Invalid ) ,
341
366
}
342
367
}
343
- Ok ( & self . sym [ start..self . next - 1 ] )
368
+ Ok ( HexNibbles {
369
+ nibbles : & self . sym [ start..self . next - 1 ] ,
370
+ } )
344
371
}
345
372
346
373
fn digit_10 ( & mut self ) -> Result < u8 , ParseError > {
@@ -577,6 +604,35 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
577
604
Ok ( ( ) )
578
605
}
579
606
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
+
580
636
/// Print the lifetime according to the previously decoded index.
581
637
/// An index of `0` always refers to `'_`, but starting with `1`,
582
638
/// indices refer to late-bound lifetimes introduced by a binder.
@@ -946,102 +1002,68 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
946
1002
}
947
1003
948
1004
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) ;
957
1006
958
- let ty_tag = parse ! ( self , next ) ;
1007
+ parse ! ( self , push_depth ) ;
959
1008
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 ( "_" ) ?,
963
1011
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
+ }
967
1018
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
+ }
981
1036
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) ?;
987
1039
}
1040
+ _ => invalid ! ( self ) ,
988
1041
}
989
1042
990
1043
self . pop_depth ( ) ;
991
1044
Ok ( ( ) )
992
1045
}
993
1046
994
- fn print_const_uint ( & mut self ) -> fmt:: Result {
1047
+ fn print_const_uint ( & mut self , ty_tag : u8 ) -> fmt:: Result {
995
1048
let hex = parse ! ( self , hex_nibbles) ;
996
1049
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) ?,
1017
1052
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
+ }
1032
1058
}
1033
1059
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) ?;
1041
1064
}
1042
- } else {
1043
- invalid ! ( self ) ;
1044
1065
}
1066
+
1045
1067
Ok ( ( ) )
1046
1068
}
1047
1069
}
@@ -1050,6 +1072,11 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
1050
1072
mod tests {
1051
1073
use std:: prelude:: v1:: * ;
1052
1074
1075
+ macro_rules! t {
1076
+ ( $a: expr, $b: expr) => { {
1077
+ assert_eq!( format!( "{}" , :: demangle( $a) ) , $b) ;
1078
+ } } ;
1079
+ }
1053
1080
macro_rules! t_nohash {
1054
1081
( $a: expr, $b: expr) => { {
1055
1082
assert_eq!( format!( "{:#}" , :: demangle( $a) ) , $b) ;
@@ -1060,6 +1087,23 @@ mod tests {
1060
1087
t_nohash!( concat!( "_RMC0" , $a) , concat!( "<" , $b, ">" ) )
1061
1088
} ;
1062
1089
}
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
+ }
1063
1107
1064
1108
#[ test]
1065
1109
fn demangle_crate_with_leading_digit ( ) {
@@ -1095,49 +1139,29 @@ mod tests {
1095
1139
}
1096
1140
1097
1141
#[ test]
1098
- fn demangle_const_generics ( ) {
1142
+ fn demangle_const_generics_preview ( ) {
1099
1143
// NOTE(eddyb) this was hand-written, before rustc had working
1100
1144
// const generics support (but the mangling format did include them).
1101
1145
t_nohash_type ! (
1102
1146
"INtC8arrayvec8ArrayVechKj7b_E" ,
1103
1147
"arrayvec::ArrayVec<u8, 123>"
1104
1148
) ;
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_" , "'∂'" ) ;
1141
1165
}
1142
1166
1143
1167
#[ test]
0 commit comments