1
1
use crate :: hir:: map:: { DefPathData , DisambiguatedDefPathData } ;
2
2
use crate :: middle:: cstore:: { ExternCrate , ExternCrateSource } ;
3
3
use crate :: middle:: region;
4
- use crate :: mir:: interpret:: { sign_extend, truncate, ConstValue , Scalar } ;
4
+ use crate :: mir:: interpret:: { sign_extend, truncate, AllocId , ConstValue , Pointer , Scalar } ;
5
5
use crate :: ty:: layout:: { Integer , IntegerExt , Size } ;
6
6
use crate :: ty:: subst:: { GenericArg , GenericArgKind , Subst } ;
7
7
use crate :: ty:: { self , DefIdTree , ParamConst , Ty , TyCtxt , TypeFoldable } ;
@@ -457,6 +457,22 @@ pub trait PrettyPrinter<'tcx>:
457
457
} )
458
458
}
459
459
460
+ fn print_type_ascribed (
461
+ mut self ,
462
+ f : impl FnOnce ( Self ) -> Result < Self , Self :: Error > ,
463
+ ty : Ty < ' tcx > ,
464
+ print_ty : bool ,
465
+ ) -> Result < Self :: Const , Self :: Error > {
466
+ self . write_str ( "{" ) ?;
467
+ self = f ( self ) ?;
468
+ if print_ty {
469
+ self . write_str ( ": " ) ?;
470
+ self = self . print_type ( ty) ?;
471
+ }
472
+ self . write_str ( "}" ) ?;
473
+ Ok ( self )
474
+ }
475
+
460
476
fn pretty_print_type ( mut self , ty : Ty < ' tcx > ) -> Result < Self :: Type , Self :: Error > {
461
477
define_scoped_cx ! ( self ) ;
462
478
@@ -893,32 +909,49 @@ pub trait PrettyPrinter<'tcx>:
893
909
Ok ( self )
894
910
}
895
911
896
- fn pretty_print_const_value (
912
+ fn pretty_print_const_scalar (
897
913
mut self ,
898
- ct : ConstValue < ' tcx > ,
914
+ scalar : Scalar ,
899
915
ty : Ty < ' tcx > ,
900
916
print_ty : bool ,
901
917
) -> Result < Self :: Const , Self :: Error > {
902
918
define_scoped_cx ! ( self ) ;
903
919
904
- if self . tcx ( ) . sess . verbose ( ) {
905
- p ! ( write( "ConstValue({:?}: {:?})" , ct, ty) ) ;
906
- return Ok ( self ) ;
907
- }
908
-
909
- let u8 = self . tcx ( ) . types . u8 ;
910
-
911
- match ( ct, & ty. kind ) {
912
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Bool ) => {
913
- p ! ( write( "{}" , if data == 0 { "false" } else { "true" } ) )
914
- }
915
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Float ( ast:: FloatTy :: F32 ) ) => {
920
+ match ( scalar, & ty. kind ) {
921
+ // Single element arrays print their element (they are `#[transparent]`) enclosed in
922
+ // square brackets.
923
+ ( _, ty:: Array ( t, n) ) if n. eval_usize ( self . tcx ( ) , ty:: ParamEnv :: empty ( ) ) == 1 => {
924
+ p ! ( write( "[" ) ) ;
925
+ self = self . pretty_print_const_scalar ( scalar, t, print_ty) ?;
926
+ p ! ( write( "]" ) ) ;
927
+ }
928
+ // Byte strings (&[u8; N])
929
+ ( Scalar :: Ptr ( ptr) , ty:: Ref ( _, ty:: TyS { kind : ty:: Array ( t, n) , .. } , _) )
930
+ if * t == self . tcx ( ) . types . u8 =>
931
+ {
932
+ let n = n. eval_usize ( self . tcx ( ) , ty:: ParamEnv :: empty ( ) ) ;
933
+ let byte_str = self
934
+ . tcx ( )
935
+ . alloc_map
936
+ . lock ( )
937
+ . unwrap_memory ( ptr. alloc_id )
938
+ . get_bytes ( & self . tcx ( ) , ptr, Size :: from_bytes ( n) )
939
+ . unwrap ( ) ;
940
+ p ! ( pretty_print_byte_str( byte_str) ) ;
941
+ }
942
+ // Bool
943
+ ( Scalar :: Raw { data : 0 , .. } , ty:: Bool ) => p ! ( write( "false" ) ) ,
944
+ ( Scalar :: Raw { data : 1 , .. } , ty:: Bool ) => p ! ( write( "true" ) ) ,
945
+ ( Scalar :: Raw { data, .. } , ty:: Bool ) => p ! ( write( "{}_bool" , data) ) ,
946
+ // Float
947
+ ( Scalar :: Raw { data, .. } , ty:: Float ( ast:: FloatTy :: F32 ) ) => {
916
948
p ! ( write( "{}f32" , Single :: from_bits( data) ) )
917
949
}
918
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Float ( ast:: FloatTy :: F64 ) ) => {
950
+ ( Scalar :: Raw { data, .. } , ty:: Float ( ast:: FloatTy :: F64 ) ) => {
919
951
p ! ( write( "{}f64" , Double :: from_bits( data) ) )
920
952
}
921
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Uint ( ui) ) => {
953
+ // Int
954
+ ( Scalar :: Raw { data, .. } , ty:: Uint ( ui) ) => {
922
955
let bit_size = Integer :: from_attr ( & self . tcx ( ) , UnsignedInt ( * ui) ) . size ( ) ;
923
956
let max = truncate ( u128:: MAX , bit_size) ;
924
957
@@ -929,7 +962,7 @@ pub trait PrettyPrinter<'tcx>:
929
962
p ! ( write( "{}{}" , data, ui_str) )
930
963
} ;
931
964
}
932
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Int ( i) ) => {
965
+ ( Scalar :: Raw { data, .. } , ty:: Int ( i) ) => {
933
966
let bit_size = Integer :: from_attr ( & self . tcx ( ) , SignedInt ( * i) ) . size ( ) . bits ( ) as u128 ;
934
967
let min = 1u128 << ( bit_size - 1 ) ;
935
968
let max = min - 1 ;
@@ -943,76 +976,140 @@ pub trait PrettyPrinter<'tcx>:
943
976
_ => p ! ( write( "{}{}" , sign_extend( data, size) as i128 , i_str) ) ,
944
977
}
945
978
}
946
- ( ConstValue :: Scalar ( Scalar :: Raw { data, .. } ) , ty:: Char ) => {
947
- p ! ( write( "{:?}" , :: std:: char :: from_u32( data as u32 ) . unwrap( ) ) )
979
+ // Char
980
+ ( Scalar :: Raw { data, .. } , ty:: Char ) => match :: std:: char:: from_u32 ( data as u32 ) {
981
+ Some ( c) => p ! ( write( "{:?}" , c) ) ,
982
+ None => p ! ( write( "{}_char" , data) ) ,
983
+ } ,
984
+ // References and pointers
985
+ ( Scalar :: Raw { data : 0 , .. } , ty:: RawPtr ( _) ) => p ! ( write( "{{null pointer}}" ) ) ,
986
+ // This is UB, but we still print it
987
+ ( Scalar :: Raw { data : 0 , .. } , ty:: Ref ( _, ty, _) ) => {
988
+ p ! ( write( "{{null reference to " ) , print( ty) , write( "}}" ) )
948
989
}
949
- ( ConstValue :: Scalar ( _) , ty:: RawPtr ( _) ) => p ! ( write( "{{pointer}}" ) ) ,
950
- ( ConstValue :: Scalar ( Scalar :: Ptr ( ptr) ) , ty:: FnPtr ( _) ) => {
990
+ ( Scalar :: Raw { data, .. } , ty:: Ref ( ..) ) | ( Scalar :: Raw { data, .. } , ty:: RawPtr ( _) ) => {
991
+ let pointer_width = self . tcx ( ) . data_layout . pointer_size . bytes ( ) ;
992
+ p ! ( write( "0x{:01$x}" , data, pointer_width as usize * 2 ) )
993
+ }
994
+ ( Scalar :: Ptr ( ptr) , ty:: FnPtr ( _) ) => {
951
995
let instance = {
952
996
let alloc_map = self . tcx ( ) . alloc_map . lock ( ) ;
953
997
alloc_map. unwrap_fn ( ptr. alloc_id )
954
998
} ;
955
999
p ! ( print_value_path( instance. def_id( ) , instance. substs) ) ;
956
1000
}
957
- _ => {
958
- let printed = if let ty:: Ref ( _, ref_ty, _) = ty. kind {
959
- let byte_str = match ( ct, & ref_ty. kind ) {
960
- ( ConstValue :: Scalar ( Scalar :: Ptr ( ptr) ) , ty:: Array ( t, n) ) if * t == u8 => {
961
- let n = n. eval_usize ( self . tcx ( ) , ty:: ParamEnv :: empty ( ) ) ;
962
- Some (
963
- self . tcx ( )
964
- . alloc_map
965
- . lock ( )
966
- . unwrap_memory ( ptr. alloc_id )
967
- . get_bytes ( & self . tcx ( ) , ptr, Size :: from_bytes ( n) )
968
- . unwrap ( ) ,
969
- )
970
- }
971
- ( ConstValue :: Slice { data, start, end } , ty:: Slice ( t) ) if * t == u8 => {
972
- // The `inspect` here is okay since we checked the bounds, and there are
973
- // no relocations (we have an active slice reference here). We don't use
974
- // this result to affect interpreter execution.
975
- Some ( data. inspect_with_undef_and_ptr_outside_interpreter ( start..end) )
976
- }
977
- _ => None ,
978
- } ;
1001
+ // For zsts just print their type as their value gives no extra information
1002
+ ( Scalar :: Raw { size : 0 , .. } , _) => p ! ( print( ty) ) ,
1003
+ // Nontrivial types with scalar bit representation
1004
+ ( Scalar :: Raw { data, size } , _) => {
1005
+ self = self . print_type_ascribed (
1006
+ |mut this| {
1007
+ write ! ( this, "0x{:01$x}" , data, size as usize * 2 ) ?;
1008
+ Ok ( this)
1009
+ } ,
1010
+ ty,
1011
+ print_ty,
1012
+ ) ?
1013
+ }
1014
+ // Any pointer values not covered by a branch above
1015
+ ( Scalar :: Ptr ( p) , _) => {
1016
+ self = self . pretty_print_const_pointer ( p, ty, print_ty) ?;
1017
+ }
1018
+ }
1019
+ Ok ( self )
1020
+ }
979
1021
980
- if let Some ( byte_str) = byte_str {
981
- p ! ( write( "b\" " ) ) ;
982
- for & c in byte_str {
983
- for e in std:: ascii:: escape_default ( c) {
984
- self . write_char ( e as char ) ?;
985
- }
986
- }
987
- p ! ( write( "\" " ) ) ;
988
- true
989
- } else if let ( ConstValue :: Slice { data, start, end } , ty:: Str ) =
990
- ( ct, & ref_ty. kind )
991
- {
992
- // The `inspect` here is okay since we checked the bounds, and there are no
993
- // relocations (we have an active `str` reference here). We don't use this
994
- // result to affect interpreter execution.
995
- let slice = data. inspect_with_undef_and_ptr_outside_interpreter ( start..end) ;
996
- let s = :: std:: str:: from_utf8 ( slice) . expect ( "non utf8 str from miri" ) ;
997
- p ! ( write( "{:?}" , s) ) ;
998
- true
999
- } else {
1000
- false
1001
- }
1002
- } else {
1003
- false
1004
- } ;
1005
- if !printed {
1006
- // fallback
1007
- p ! ( write( "{:?}" , ct) ) ;
1008
- if print_ty {
1009
- p ! ( write( ": " ) , print( ty) ) ;
1010
- }
1011
- }
1022
+ /// This is overridden for MIR printing because we only want to hide alloc ids from users, not
1023
+ /// from MIR where it is actually useful.
1024
+ fn pretty_print_const_pointer (
1025
+ self ,
1026
+ _: Pointer ,
1027
+ ty : Ty < ' tcx > ,
1028
+ print_ty : bool ,
1029
+ ) -> Result < Self :: Const , Self :: Error > {
1030
+ self . print_type_ascribed (
1031
+ |mut this| {
1032
+ this. write_str ( "pointer" ) ?;
1033
+ Ok ( this)
1034
+ } ,
1035
+ ty,
1036
+ print_ty,
1037
+ )
1038
+ }
1039
+
1040
+ fn pretty_print_byte_str ( mut self , byte_str : & ' tcx [ u8 ] ) -> Result < Self :: Const , Self :: Error > {
1041
+ define_scoped_cx ! ( self ) ;
1042
+ p ! ( write( "b\" " ) ) ;
1043
+ for & c in byte_str {
1044
+ for e in std:: ascii:: escape_default ( c) {
1045
+ self . write_char ( e as char ) ?;
1012
1046
}
1013
- } ;
1047
+ }
1048
+ p ! ( write( "\" " ) ) ;
1014
1049
Ok ( self )
1015
1050
}
1051
+
1052
+ fn pretty_print_const_value (
1053
+ mut self ,
1054
+ ct : ConstValue < ' tcx > ,
1055
+ ty : Ty < ' tcx > ,
1056
+ print_ty : bool ,
1057
+ ) -> Result < Self :: Const , Self :: Error > {
1058
+ define_scoped_cx ! ( self ) ;
1059
+
1060
+ if self . tcx ( ) . sess . verbose ( ) {
1061
+ p ! ( write( "ConstValue({:?}: {:?})" , ct, ty) ) ;
1062
+ return Ok ( self ) ;
1063
+ }
1064
+
1065
+ let u8_type = self . tcx ( ) . types . u8 ;
1066
+
1067
+ match ( ct, & ty. kind ) {
1068
+ ( ConstValue :: Scalar ( scalar) , _) => self . pretty_print_const_scalar ( scalar, ty, print_ty) ,
1069
+ (
1070
+ ConstValue :: Slice { data, start, end } ,
1071
+ ty:: Ref ( _, ty:: TyS { kind : ty:: Slice ( t) , .. } , _) ,
1072
+ ) if * t == u8_type => {
1073
+ // The `inspect` here is okay since we checked the bounds, and there are
1074
+ // no relocations (we have an active slice reference here). We don't use
1075
+ // this result to affect interpreter execution.
1076
+ let byte_str = data. inspect_with_undef_and_ptr_outside_interpreter ( start..end) ;
1077
+ self . pretty_print_byte_str ( byte_str)
1078
+ }
1079
+ (
1080
+ ConstValue :: Slice { data, start, end } ,
1081
+ ty:: Ref ( _, ty:: TyS { kind : ty:: Str , .. } , _) ,
1082
+ ) => {
1083
+ // The `inspect` here is okay since we checked the bounds, and there are no
1084
+ // relocations (we have an active `str` reference here). We don't use this
1085
+ // result to affect interpreter execution.
1086
+ let slice = data. inspect_with_undef_and_ptr_outside_interpreter ( start..end) ;
1087
+ let s = :: std:: str:: from_utf8 ( slice) . expect ( "non utf8 str from miri" ) ;
1088
+ p ! ( write( "{:?}" , s) ) ;
1089
+ Ok ( self )
1090
+ }
1091
+ ( ConstValue :: ByRef { alloc, offset } , ty:: Array ( t, n) ) if * t == u8_type => {
1092
+ let n = n. eval_usize ( self . tcx ( ) , ty:: ParamEnv :: empty ( ) ) ;
1093
+ let n = Size :: from_bytes ( n) ;
1094
+ let ptr = Pointer :: new ( AllocId ( 0 ) , offset) ;
1095
+
1096
+ let byte_str = alloc. get_bytes ( & self . tcx ( ) , ptr, n) . unwrap ( ) ;
1097
+ p ! ( write( "*" ) ) ;
1098
+ p ! ( pretty_print_byte_str( byte_str) ) ;
1099
+ Ok ( self )
1100
+ }
1101
+ // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
1102
+ // their fields instead of just dumping the memory.
1103
+ _ => {
1104
+ // fallback
1105
+ p ! ( write( "{:?}" , ct) ) ;
1106
+ if print_ty {
1107
+ p ! ( write( ": " ) , print( ty) ) ;
1108
+ }
1109
+ Ok ( self )
1110
+ }
1111
+ }
1112
+ }
1016
1113
}
1017
1114
1018
1115
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
@@ -1024,6 +1121,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
1024
1121
1025
1122
empty_path : bool ,
1026
1123
in_value : bool ,
1124
+ pub print_alloc_ids : bool ,
1027
1125
1028
1126
used_region_names : FxHashSet < Symbol > ,
1029
1127
region_index : usize ,
@@ -1054,6 +1152,7 @@ impl<F> FmtPrinter<'a, 'tcx, F> {
1054
1152
fmt,
1055
1153
empty_path : false ,
1056
1154
in_value : ns == Namespace :: ValueNS ,
1155
+ print_alloc_ids : false ,
1057
1156
used_region_names : Default :: default ( ) ,
1058
1157
region_index : 0 ,
1059
1158
binder_depth : 0 ,
@@ -1382,6 +1481,45 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
1382
1481
ty:: ReStatic | ty:: ReEmpty ( _) | ty:: ReClosureBound ( _) => true ,
1383
1482
}
1384
1483
}
1484
+
1485
+ fn pretty_print_const_pointer (
1486
+ self ,
1487
+ p : Pointer ,
1488
+ ty : Ty < ' tcx > ,
1489
+ print_ty : bool ,
1490
+ ) -> Result < Self :: Const , Self :: Error > {
1491
+ self . print_type_ascribed (
1492
+ |mut this| {
1493
+ define_scoped_cx ! ( this) ;
1494
+ if this. print_alloc_ids {
1495
+ p ! ( write( "{:?}" , p) ) ;
1496
+ } else {
1497
+ p ! ( write( "pointer" ) ) ;
1498
+ }
1499
+ Ok ( this)
1500
+ } ,
1501
+ ty,
1502
+ print_ty,
1503
+ )
1504
+ }
1505
+
1506
+ fn print_type_ascribed (
1507
+ mut self ,
1508
+ f : impl FnOnce ( Self ) -> Result < Self , Self :: Error > ,
1509
+ ty : Ty < ' tcx > ,
1510
+ print_ty : bool ,
1511
+ ) -> Result < Self :: Const , Self :: Error > {
1512
+ self . write_str ( "{" ) ?;
1513
+ self = f ( self ) ?;
1514
+ if print_ty {
1515
+ self . write_str ( ": " ) ?;
1516
+ let was_in_value = std:: mem:: replace ( & mut self . in_value , false ) ;
1517
+ self = self . print_type ( ty) ?;
1518
+ self . in_value = was_in_value;
1519
+ }
1520
+ self . write_str ( "}" ) ?;
1521
+ Ok ( self )
1522
+ }
1385
1523
}
1386
1524
1387
1525
// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
0 commit comments